From f09eca8db0184aeb6b9718a987cfb3653ad7c4ae Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 9 Jul 2013 20:16:39 +0200 Subject: netfilter: ctnetlink: fix incorrect NAT expectation dumping nf_ct_expect_alloc leaves unset the expectation NAT fields. However, ctnetlink_exp_dump_expect expects them to be zeroed in case they are not used, which may not be the case. This results in dumping the NAT tuple of the expectation when it should not. Fix it by zeroing the NAT fields of the expectation. Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index c63b618..4fd1ca9 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -293,6 +293,11 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, sizeof(exp->tuple.dst.u3) - len); exp->tuple.dst.u.all = *dst; + +#ifdef CONFIG_NF_NAT_NEEDED + memset(&exp->saved_addr, 0, sizeof(exp->saved_addr)); + memset(&exp->saved_proto, 0, sizeof(exp->saved_proto)); +#endif } EXPORT_SYMBOL_GPL(nf_ct_expect_init); -- cgit v0.10.2 From baf60efa585c78b269f0097288868a51ccc61f55 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Jul 2013 19:22:19 -0700 Subject: netfilter: xt_socket: fix broken v0 support commit 681f130f39e10 ("netfilter: xt_socket: add XT_SOCKET_NOWILDCARD flag") added a potential NULL dereference if an old iptables package uses v0 of the match. Fix this by removing the test on @info in fast path. IPv6 can remove the test as well, as it uses v1 or v2. Reported-by: Neal Cardwell Signed-off-by: Eric Dumazet Cc: Patrick McHardy Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index f8b7191..20b1591 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -172,7 +172,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, /* Ignore non-transparent sockets, if XT_SOCKET_TRANSPARENT is used */ - if (info && info->flags & XT_SOCKET_TRANSPARENT) + if (info->flags & XT_SOCKET_TRANSPARENT) transparent = ((sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->transparent) || (sk->sk_state == TCP_TIME_WAIT && @@ -196,7 +196,11 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par, static bool socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par) { - return socket_match(skb, par, NULL); + static struct xt_socket_mtinfo1 xt_info_v0 = { + .flags = 0, + }; + + return socket_match(skb, par, &xt_info_v0); } static bool @@ -314,7 +318,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par) /* Ignore non-transparent sockets, if XT_SOCKET_TRANSPARENT is used */ - if (info && info->flags & XT_SOCKET_TRANSPARENT) + if (info->flags & XT_SOCKET_TRANSPARENT) transparent = ((sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->transparent) || (sk->sk_state == TCP_TIME_WAIT && -- cgit v0.10.2 From a0ec570f4f69c4cb700d743a915096c2c8f56a99 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Tue, 25 Jun 2013 09:17:17 +0200 Subject: nl80211: fix mgmt tx status and testmode reporting for netns These two events were sent to the default network namespace. This caused AP mode in a non-default netns to not work correctly. Mgmt tx status was multicasted to a different (default) netns instead of the one the AP was in. Cc: stable@vger.kernel.org Signed-off-by: Michal Kazior Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1cc47ac..9fb8820 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6613,12 +6613,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) { + struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; void *hdr = ((void **)skb->cb)[1]; struct nlattr *data = ((void **)skb->cb)[2]; nla_nest_end(skb, data); genlmsg_end(skb, hdr); - genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0, + nl80211_testmode_mcgrp.id, gfp); } EXPORT_SYMBOL(cfg80211_testmode_event); #endif @@ -10064,7 +10066,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); return; nla_put_failure: -- cgit v0.10.2 From 923a0e7dee8c436108279568cf34444749ac796f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Jun 2013 11:38:54 +0200 Subject: cfg80211: fix bugs in new SME implementation When splitting the SME implementation from the MLME code, I introduced a few bugs: * association failures no longer sent a connect-failure event * getting disassociated from the AP caused deauth to be sent but state wasn't cleaned up, leading to warnings * authentication failures weren't cleaned up properly, causing new connection attempts to warn and fail Fix these bugs. Signed-off-by: Johannes Berg diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 1d3cfb1..81c8a10 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -34,8 +34,10 @@ struct cfg80211_conn { CFG80211_CONN_SCAN_AGAIN, CFG80211_CONN_AUTHENTICATE_NEXT, CFG80211_CONN_AUTHENTICATING, + CFG80211_CONN_AUTH_FAILED, CFG80211_CONN_ASSOCIATE_NEXT, CFG80211_CONN_ASSOCIATING, + CFG80211_CONN_ASSOC_FAILED, CFG80211_CONN_DEAUTH, CFG80211_CONN_CONNECTED, } state; @@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) NULL, 0, params->key, params->key_len, params->key_idx, NULL, 0); + case CFG80211_CONN_AUTH_FAILED: + return -ENOTCONN; case CFG80211_CONN_ASSOCIATE_NEXT: BUG_ON(!rdev->ops->assoc); wdev->conn->state = CFG80211_CONN_ASSOCIATING; @@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) WLAN_REASON_DEAUTH_LEAVING, false); return err; + case CFG80211_CONN_ASSOC_FAILED: + cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING, false); + return -ENOTCONN; case CFG80211_CONN_DEAUTH: cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, NULL, 0, WLAN_REASON_DEAUTH_LEAVING, false); + /* free directly, disconnected event already sent */ + cfg80211_sme_free(wdev); return 0; default: return 0; @@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status) return true; } - wdev->conn->state = CFG80211_CONN_DEAUTH; + wdev->conn->state = CFG80211_CONN_ASSOC_FAILED; schedule_work(&rdev->conn_work); return false; } @@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev) void cfg80211_sme_auth_timeout(struct wireless_dev *wdev) { - cfg80211_sme_free(wdev); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + if (!wdev->conn) + return; + + wdev->conn->state = CFG80211_CONN_AUTH_FAILED; + schedule_work(&rdev->conn_work); } void cfg80211_sme_disassoc(struct wireless_dev *wdev) @@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev) void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev) { - cfg80211_sme_disassoc(wdev); + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + + if (!wdev->conn) + return; + + wdev->conn->state = CFG80211_CONN_ASSOC_FAILED; + schedule_work(&rdev->conn_work); } static int cfg80211_sme_connect(struct wireless_dev *wdev, -- cgit v0.10.2 From f77b86d7d3acf9dfcb5ee834628d12207584b2cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 24 Jun 2013 15:43:38 +0200 Subject: regulatory: add missing rtnl locking restore_regulatory_settings() requires the RTNL to be held, add the missing locking in reg_timeout_work(). Signed-off-by: Johannes Berg diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5a24c98..5a950f3 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2279,7 +2279,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) static void reg_timeout_work(struct work_struct *work) { REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); + rtnl_lock(); restore_regulatory_settings(true); + rtnl_unlock(); } int __init regulatory_init(void) -- cgit v0.10.2 From 1cd158573951f737fbc878a35cb5eb47bf9af3d5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 28 Jun 2013 21:04:35 +0200 Subject: mac80211/minstrel_ht: fix cck rate sampling The CCK group needs special treatment to set the right flags and rate index. Add this missing check to prevent setting broken rates for tx packets. Cc: stable@vger.kernel.org # 3.10 Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 5b2d301..f5aed96 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + rate->count = 1; + + if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { + int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); + rate->idx = mp->cck_rates[idx]; + rate->flags = 0; + return; + } + rate->idx = sample_idx % MCS_GROUP_RATES + (sample_group->streams - 1) * MCS_GROUP_RATES; rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; - rate->count = 1; } static void -- cgit v0.10.2 From e13bae4f807401729b3f27c7e882a96b8b292809 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 8 Jul 2013 10:43:31 +0200 Subject: mac80211: fix ethtool stats for non-station interfaces As reported in https://bugzilla.kernel.org/show_bug.cgi?id=60514, the station loop never initialises 'sinfo' and therefore adds up a stack values, leaking stack information (the number of times it adds values is easily obtained another way.) Fix this by initialising the sinfo for each station to add. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8184d12..43dd752 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -666,6 +666,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, if (sta->sdata->dev != dev) continue; + sinfo.filled = 0; + sta_set_sinfo(sta, &sinfo); i = 0; ADD_STA_STATS(sta); } -- cgit v0.10.2 From 83374fe9de455e37c2a039603d2538eb77e8ec4d Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Thu, 11 Jul 2013 18:24:03 +0800 Subject: nl80211: fix the setting of RSSI threshold value for mesh RSSI threshold value used for mesh peering should be in negative value. After range checks to mesh parameters is introduced, this is not allowed. Fix this. Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9fb8820..25d217d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4770,9 +4770,9 @@ do { \ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1, mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255, + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0, mask, NL80211_MESHCONF_RSSI_THRESHOLD, - nla_get_u32); + nla_get_s32); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16, mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16); -- cgit v0.10.2 From 6b0f32745dcfba01d7be33acd1b40306c7a914c6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jul 2013 22:33:26 +0200 Subject: mac80211: fix duplicate retransmission detection The duplicate retransmission detection code in mac80211 erroneously attempts to do the check for every frame, even frames that don't have a sequence control field or that don't use it (QoS-Null frames.) This is problematic because it causes the code to access data beyond the end of the SKB and depending on the data there will drop packets erroneously. Correct the code to not do duplicate detection for such frames. I found this error while testing AP powersave, it lead to retransmitted PS-Poll frames being dropped entirely as the data beyond the end of the SKB was always zero. Cc: stable@vger.kernel.org [all versions] Signed-off-by: Johannes Berg diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 23dbcfc..2c5a79b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ - if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { + /* + * Drop duplicate 802.11 retransmissions + * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") + */ + if (rx->skb->len >= 24 && rx->sta && + !ieee80211_is_ctl(hdr->frame_control) && + !ieee80211_is_qos_nullfunc(hdr->frame_control) && + !is_multicast_ether_addr(hdr->addr1)) { if (unlikely(ieee80211_has_retry(hdr->frame_control) && rx->sta->last_seq_ctrl[rx->seqno_idx] == hdr->seq_ctrl)) { -- cgit v0.10.2 From b7327d89ae694a89f9934d428bde520b77b3131c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 24 Jun 2013 15:44:03 +0300 Subject: iwlwifi: mvm: unregister leds when registration failed This was missing and prevented any further attempts to load the module. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e08683b..cab2f0c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (ret) return ret; - return ieee80211_register_hw(mvm->hw); + ret = ieee80211_register_hw(mvm->hw); + if (ret) + iwl_mvm_leds_exit(mvm); + + return ret; } static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, -- cgit v0.10.2 From 707aee401d2467baa785a697f40a6e2d9ee79ad5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 3 May 2013 18:58:16 +0200 Subject: iwlwifi: dvm: don't send BT_CONFIG on devices w/o Bluetooth The BT_CONFIG command that is sent to the device during startup will enable BT coex unless the module parameter turns it off, but on devices without Bluetooth this may cause problems, as reported in Redhat BZ 885407. Fix this by sending the BT_CONFIG command only when the device has Bluetooth. Cc: stable@vger.kernel.org Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 3952ddf..1531a4f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv) BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); if (ret) return ret; - } else { + } else if (priv->lib->bt_params) { /* * default is 2-wire BT coexexistence support */ -- cgit v0.10.2 From 0ecb376375d662987eba2f6e3bfd4bd532bb3907 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Sun, 23 Jun 2013 20:31:07 +0300 Subject: iwlwifi: mvm: Fix VIF specific debugfs directory creation Avoid creating VIF specific debugfs directory if already exist. This may happen when, for example, resetting hw, suspend-resume. Signed-off-by: Alexander Bondar Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e56ed2a..c24a744 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); char buf[100]; - if (!dbgfs_dir) + /* + * Check if debugfs directory already exist before creating it. + * This may happen when, for example, resetting hw or suspend-resume + */ + if (!dbgfs_dir || mvmvif->dbgfs_dir) return; mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); -- cgit v0.10.2 From 93a426673fbfeae7fa6b27008828e2ac4c08dbee Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 2 Jul 2013 13:35:35 +0300 Subject: iwlwifi: mvm: fix L2P BA ressources leak We didn't release the Rx AMPDU ressources properly. This bug led to firmware assert after 16 BA sessions. Cc: [3.9+] Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 62fe520..b6ab076 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -621,8 +621,12 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); cmd.sta_id = mvm_sta->sta_id; cmd.add_modify = STA_MODE_MODIFY; - cmd.add_immediate_ba_tid = (u8) tid; - cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); + if (start) { + cmd.add_immediate_ba_tid = (u8) tid; + cmd.add_immediate_ba_ssn = cpu_to_le16(ssn); + } else { + cmd.remove_immediate_ba_tid = (u8) tid; + } cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID : STA_MODIFY_REMOVE_BA_TID; -- cgit v0.10.2 From 113a04470d9178170a5d1aa165809515884f39a8 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 2 Jul 2013 14:16:38 +0300 Subject: iwlwifi: mvm: track the number of Rx BA sessions The firmware / HW can't support more than 16 Rx BA sessions. Deny any attemps to open more sessions than that. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index cab2f0c..1a4a032 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -389,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ieee80211_wake_queues(mvm->hw); mvm->vif_count = 0; + mvm->rx_ba_sessions = 0; } static int iwl_mvm_mac_start(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d40d7db..420e82d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -419,6 +419,7 @@ struct iwl_mvm { struct work_struct sta_drained_wk; unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; atomic_t pending_frames[IWL_MVM_STATION_COUNT]; + u8 rx_ba_sessions; /* configured by mac80211 */ u32 rts_threshold; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index b6ab076..85d4bbe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta) return ret; } +#define IWL_MAX_RX_BA_SESSIONS 16 + int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start) { @@ -618,6 +620,11 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lockdep_assert_held(&mvm->mutex); + if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) { + IWL_WARN(mvm, "Not enough RX BA SESSIONS\n"); + return -ENOSPC; + } + cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); cmd.sta_id = mvm_sta->sta_id; cmd.add_modify = STA_MODE_MODIFY; @@ -652,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, break; } + if (!ret) { + if (start) + mvm->rx_ba_sessions++; + else if (mvm->rx_ba_sessions > 0) + /* check that restart flow didn't zero the counter */ + mvm->rx_ba_sessions--; + } + return ret; } -- cgit v0.10.2 From 48bc13072109ea58465542aa1ee31b4e1065468a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jul 2013 15:55:29 +0200 Subject: iwlwifi: mvm: refuse connection to APs with BI < 16 Due to a firmware bug, it crashes when the beacon interval is smaller than 16. Avoid this by refusing the station state change creating the AP station, causing mac80211 to abandon the attempt to connect to the AP, and eventually wpa_s to blacklist it. Cc: stable@vger.kernel.org Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 1a4a032..1eedc42 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1011,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { + /* + * Firmware bug - it'll crash if the beacon interval is less + * than 16. We can't avoid connecting at all, so refuse the + * station state change, this will cause mac80211 to abandon + * attempts to connect to this AP, and eventually wpa_s will + * blacklist the AP... + */ + if (vif->type == NL80211_IFTYPE_STATION && + vif->bss_conf.beacon_int < 16) { + IWL_ERR(mvm, + "AP %pM beacon interval is %d, refusing due to firmware bug!\n", + sta->addr, vif->bss_conf.beacon_int); + ret = -EINVAL; + goto out_unlock; + } ret = iwl_mvm_add_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { @@ -1043,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else { ret = -EIO; } + out_unlock: mutex_unlock(&mvm->mutex); return ret; -- cgit v0.10.2 From fe04e83706037802c502ea41c0d1799ec35fc0d7 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 4 Jul 2013 15:17:48 +0300 Subject: iwlwifi: mvm: fix bug in scan ssid Increment index in each iteration. Without this increment we are overriding the added SSIDs and we will send only the last SSId and (n_ssids - 1) broadcast probes. Cc: [3.9+] Signed-off-by: David Spinadel Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 2157b0f..8023dee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, { int fw_idx, req_idx; - fw_idx = 0; - for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) { + for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0; + req_idx--, fw_idx++) { cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; memcpy(cmd->direct_scan[fw_idx].ssid, -- cgit v0.10.2 From a590ad411891de551e6de1b51ea635c0484148d6 Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Thu, 4 Jul 2013 15:22:26 +0300 Subject: iwlwifi: mvm: remove extra SSID from probe request Bits 1-21 in this channel type attributes are indication for which SSID is going to be sent on this channel. Since the first SSID is sent implicitly in the probe request, we don't need to toggle its bit here. Signed-off-by: David Spinadel Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 8023dee..268f027 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, * just to notify that this scan is active and not passive. * In order to notify the FW of the number of SSIDs we wish to scan (including * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). + * one for each SSID, and set the active bit (first). The first SSID is already + * included in the probe template, so we need to set only req->n_ssids - 1 bits + * in addition to the first bit. */ static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids) { @@ -179,7 +181,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, __le32 chan_type_value; if (req->n_ssids > 0) - chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1); + chan_type_value = cpu_to_le32(BIT(req->n_ssids) - 1); else chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE; -- cgit v0.10.2 From 5c9fc93bc9bc417418fc1b6366833ae6a07b804d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 15 Jul 2013 14:35:06 +0200 Subject: mac80211/minstrel: fix NULL pointer dereference issue When priv_sta == NULL, mi->prev_sample is dereferenced too early. Move the assignment further down, after the rate_control_send_low call. Reported-by: Krzysztof Mazur Cc: stable@vger.kernel.org # 3.10 Signed-off-by: Felix Fietkau Signed-off-by: Johannes Berg diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index ac7ef54..e6512e2 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, struct minstrel_rate *msr, *mr; unsigned int ndx; bool mrr_capable; - bool prev_sample = mi->prev_sample; + bool prev_sample; int delta; int sampling_ratio; @@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, (mi->sample_count + mi->sample_deferred / 2); /* delta < 0: no sampling required */ + prev_sample = mi->prev_sample; mi->prev_sample = false; if (delta < 0 || (!mrr_capable && prev_sample)) return; -- cgit v0.10.2 From c1f01be4060b6f1932e428c209a6c14d6b22fc1c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Wed, 17 Jul 2013 10:51:22 +0300 Subject: usb: musb: fix resource passed from glue layer to musb some MUSB incarnations, such as those governed by omap2430.c and tusb6010.c, have three resources, not two. Fix the bug created by commit 09fc7d2 (usb: musb: fix incorrect usage of resource pointer) where only two of the three resources would be passed to musb_core.c [ balbi@ti.com : add tusb6010.c to original patch ] Tested-by: Aaro Koskinen Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 6708a3b..f44e8b5 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -481,7 +481,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32); static int omap2430_probe(struct platform_device *pdev) { - struct resource musb_resources[2]; + struct resource musb_resources[3]; struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; struct omap_musb_board_data *data; struct platform_device *musb; @@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + ret = platform_device_add_resources(musb, musb_resources, ARRAY_SIZE(musb_resources)); if (ret) { diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2c06a89..6f8a9ca 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1156,7 +1156,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32); static int tusb_probe(struct platform_device *pdev) { - struct resource musb_resources[2]; + struct resource musb_resources[3]; struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; struct platform_device *musb; struct tusb6010_glue *glue; @@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev) musb_resources[1].end = pdev->resource[1].end; musb_resources[1].flags = pdev->resource[1].flags; + musb_resources[2].name = pdev->resource[2].name; + musb_resources[2].start = pdev->resource[2].start; + musb_resources[2].end = pdev->resource[2].end; + musb_resources[2].flags = pdev->resource[2].flags; + ret = platform_device_add_resources(musb, musb_resources, ARRAY_SIZE(musb_resources)); if (ret) { -- cgit v0.10.2 From bcfb879432094c267c35a7ff75d953d3a66c193a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 28 Jun 2013 09:12:53 -0500 Subject: rtlwifi: Initialize power-setting callback for USB devices Commit a269913c5 entitled "rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue" has two bugs for USB drivers. Firstly, the work queue in question was not initialized. Secondly, the callback routine used by this queue is contained within the file used for PCI devices. As a result, it is not available for architectures without PCI hardware. Signed-off-by: Larry Finger Reported-by: Richard Genoud Tested-by: Richard Genoud Cc: Richard Genoud Cc: Stable [3.10] Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index c97e9d3..e70b4ff 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1008,19 +1008,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) return; } -static void rtl_lps_change_work_callback(struct work_struct *work) -{ - struct rtl_works *rtlworks = - container_of(work, struct rtl_works, lps_change_work); - struct ieee80211_hw *hw = rtlworks->hw; - struct rtl_priv *rtlpriv = rtl_priv(hw); - - if (rtlpriv->enter_ps) - rtl_lps_enter(hw); - else - rtl_lps_leave(hw); -} - static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 884bcea..71e917d 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -611,6 +611,18 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); } +void rtl_lps_change_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, lps_change_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->enter_ps) + rtl_lps_enter(hw); + else + rtl_lps_leave(hw); +} void rtl_swlps_wq_callback(void *data) { diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index 4d682b7..88bd76e 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw); void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state); void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_lps_change_work_callback(struct work_struct *work); #endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a3532e0..1feebdc 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -1070,6 +1070,8 @@ int rtl_usb_probe(struct usb_interface *intf, spin_lock_init(&rtlpriv->locks.usb_lock); INIT_WORK(&rtlpriv->works.fill_h2c_cmd, rtl_fill_h2c_cmd_work_callback); + INIT_WORK(&rtlpriv->works.lps_change_work, + rtl_lps_change_work_callback); rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); -- cgit v0.10.2 From a4943ccbc316fd74d3612d7a5984a91ab7e5dc8c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 30 Jun 2013 12:02:13 +0200 Subject: ath9k: fix tx pending frames accounting for dropped packets When dropping packets that have gone far enough into the tx path, the pending frame counter needs to be decreased. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index c59ae43..9279927 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, ARRAY_SIZE(bf->rates)); } +static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, + struct sk_buff *skb) +{ + int q; + + q = skb_get_queue_mapping(skb); + if (txq == sc->tx.uapsdq) + txq = sc->tx.txq_map[q]; + + if (txq != sc->tx.txq_map[q]) + return; + + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; + + if (txq->stopped && + txq->pending_frames < sc->tx.txq_max_pending[q]) { + ieee80211_wake_queue(sc->hw, q); + txq->stopped = false; + } +} + static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; @@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) if (!bf) { bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, if (!bf) { __skb_unlink(skb, &tid->buf_q); + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); continue; } @@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); ieee80211_free_txskb(sc->hw, skb); return; } @@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) { + ath_txq_skb_done(sc, txq, skb); if (txctl->paprd) dev_kfree_skb_any(skb); else @@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; - int q, padpos, padsize; + int padpos, padsize; unsigned long flags; ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb); @@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, spin_unlock_irqrestore(&sc->sc_pm_lock, flags); __skb_queue_tail(&txq->complete_q, skb); - - q = skb_get_queue_mapping(skb); - if (txq == sc->tx.uapsdq) - txq = sc->tx.txq_map[q]; - - if (txq == sc->tx.txq_map[q]) { - if (WARN_ON(--txq->pending_frames < 0)) - txq->pending_frames = 0; - - if (txq->stopped && - txq->pending_frames < sc->tx.txq_max_pending[q]) { - ieee80211_wake_queue(sc->hw, q); - txq->stopped = false; - } - } + ath_txq_skb_done(sc, txq, skb); } static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, -- cgit v0.10.2 From 9494849e53e74048ee14d512feade01db402eef7 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Tue, 2 Jul 2013 00:43:42 +0400 Subject: ath9k_htc: fix data race between request_firmware_nowait() callback and suspend() ath9k_hif_usb_probe() requests firmware asynchronically and there is some initialization postponed till firmware is ready. In particular, ath9k_hif_usb_firmware_cb() callback initializes hif_dev->tx.tx_buf and hif_dev->tx.tx_pending lists. At the same time, ath9k_hif_usb_suspend() iterates that lists through ath9k_hif_usb_dealloc_urbs(). If suspend happens before request_firmware_nowait() callback is called, it can lead to oops. Similar issue could be in ath9k_hif_usb_disconnect(), but it is prevented using hif_dev->fw_done completion and HIF_USB_READY flag. The patch extends this approach to suspend() as well. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 9e582e1..2469db5 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev) struct device *dev = &hif_dev->udev->dev; struct device *parent = dev->parent; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); if (parent) device_lock(parent); @@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) release_firmware(fw); hif_dev->flags |= HIF_USB_READY; - complete(&hif_dev->fw_done); + complete_all(&hif_dev->fw_done); return; @@ -1316,7 +1316,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface, if (!(hif_dev->flags & HIF_USB_START)) ath9k_htc_suspend(hif_dev->htc_handle); - ath9k_hif_usb_dealloc_urbs(hif_dev); + wait_for_completion(&hif_dev->fw_done); + + if (hif_dev->flags & HIF_USB_READY) + ath9k_hif_usb_dealloc_urbs(hif_dev); return 0; } -- cgit v0.10.2 From b01a60be7a4a161ac0a11df30569d21a20795aef Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 5 Jul 2013 17:43:56 +0200 Subject: ssb: fix alignment of struct bcma_device_id The ARM OABI and EABI disagree on the alignment of structures with small members, so module init tools may interpret the ssb device table incorrectly, as shown by this warning when building the b43 device driver in an OABI kernel: FATAL: drivers/net/wireless/b43/b43: sizeof(struct ssb_device_id)=6 is not a modulo of the size of section __mod_ssb_device_table=88. Forcing the default (EABI) alignment on the structure makes this problem go away. Since the ssb_device_id may have the same problem, better fix both structures. Signed-off-by: Arnd Bergmann Cc: Russell King Cc: John W. Linville Cc: Michael Buesch Cc: Larry Finger Signed-off-by: John W. Linville diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b62d4af..45e9214 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -361,7 +361,8 @@ struct ssb_device_id { __u16 vendor; __u16 coreid; __u8 revision; -}; + __u8 __pad; +} __attribute__((packed, aligned(2))); #define SSB_DEVICE(_vendor, _coreid, _revision) \ { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } #define SSB_DEVTABLE_END \ @@ -377,7 +378,7 @@ struct bcma_device_id { __u16 id; __u8 rev; __u8 class; -}; +} __attribute__((packed,aligned(2))); #define BCMA_CORE(_manuf, _id, _rev, _class) \ { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } #define BCMA_CORETABLE_END \ -- cgit v0.10.2 From 6a08483926bf26d9e5274b4dd5086d583971f1ea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jul 2013 23:03:35 +0200 Subject: rt2x00: RT2X00 should depend on HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `rt2x00queue_unmap_skb': drivers/net/wireless/rt2x00/rt2x00queue.c:129: undefined reference to `dma_unmap_single' drivers/net/wireless/rt2x00/rt2x00queue.c:133: undefined reference to `dma_unmap_single' drivers/built-in.o: In function `rt2x00queue_map_txskb': drivers/net/wireless/rt2x00/rt2x00queue.c:112: undefined reference to `dma_map_single' drivers/net/wireless/rt2x00/rt2x00queue.c:115: undefined reference to `dma_mapping_error' drivers/built-in.o: In function `rt2x00queue_alloc_rxskb': drivers/net/wireless/rt2x00/rt2x00queue.c:93: undefined reference to `dma_map_single' drivers/net/wireless/rt2x00/rt2x00queue.c:95: undefined reference to `dma_mapping_error' Signed-off-by: Geert Uytterhoeven Cc: linux-wireless@vger.kernel.org Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 9b915d3..3e60a31 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -1,6 +1,6 @@ menuconfig RT2X00 tristate "Ralink driver support" - depends on MAC80211 + depends on MAC80211 && HAS_DMA ---help--- This will enable the support for the Ralink drivers, developed in the rt2x00 project . -- cgit v0.10.2 From f287cbd01f2e8e1b325b96233c373619c2d25ee2 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 11 Jul 2013 09:19:13 -0400 Subject: ath5k: fix extra set bit in multicast mask Bit 32 was always set which looks to have been accidental, according to git history. Signed-off-by: Bob Copeland Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 81b686c..40825d4 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr *ha; mfilt[0] = 0; - mfilt[1] = 1; + mfilt[1] = 0; netdev_hw_addr_list_for_each(ha, mc_list) { /* calculate XOR of eight 6-bit values */ -- cgit v0.10.2 From 6f334c2b3966f10cbd089bb124ec0e114d8d8c77 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 12 Jul 2013 15:32:15 -0500 Subject: rtlwifi: Fix build errors for unusual cases The present build configuration for the rtlwifi family of drivers will fail under two known conditions: (1) If rtlwifi is selected without selecting any of the dependent drivers, there are errors in the build. (2) If the PCI drivers are built into the kernel and the USB drivers are modules, or vice versa, there are missing globals. The first condition is fixed by never building rtlwifi unless at least one of the device drivers is selected. The second failure is fixed by splitting the PCI and USB codes out of rtlwifi, and creating their own mini drivers. If the drivers that use them are modules, they will also be modules. Although a number of files are touched by this patch, only Makefile and Kconfig have undergone significant changes. The only modifications to the other files were to export entry points needed by the new rtl_pci and rtl_usb units, or to rename two variables that had names that were likely to cause namespace collisions. Reported-by: Fengguang Wu [Condition 1] Reported-by: Ben Hutchings [Condition 2] Signed-off-by: Larry Finger Cc: Ben Hutchings Cc: Fengguang Wu Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig index 7253de3..c2ffce7 100644 --- a/drivers/net/wireless/rtlwifi/Kconfig +++ b/drivers/net/wireless/rtlwifi/Kconfig @@ -1,27 +1,20 @@ -config RTLWIFI - tristate "Realtek wireless card support" - depends on MAC80211 - select FW_LOADER - ---help--- - This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE - drivers. This module does nothing by itself - the various front-end - drivers need to be enabled to support any desired devices. - - If you choose to build as a module, it'll be called rtlwifi. - -config RTLWIFI_DEBUG - bool "Debugging output for rtlwifi driver family" - depends on RTLWIFI +menuconfig RTL_CARDS + tristate "Realtek rtlwifi family of devices" + depends on MAC80211 && (PCI || USB) default y ---help--- - To use the module option that sets the dynamic-debugging level for, - the front-end driver, this parameter must be "Y". For memory-limited - systems, choose "N". If in doubt, choose "Y". + This option will enable support for the Realtek mac80211-based + wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de, + rtl8723eu, and rtl8188eu share some common code. + +if RTL_CARDS config RTL8192CE tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI select RTL8192C_COMMON + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe wireless network adapters. @@ -30,7 +23,9 @@ config RTL8192CE config RTL8192SE tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe wireless network adapters. @@ -39,7 +34,9 @@ config RTL8192SE config RTL8192DE tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe wireless network adapters. @@ -48,7 +45,9 @@ config RTL8192DE config RTL8723AE tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8723AE 802.11n PCIe wireless network adapters. @@ -57,7 +56,9 @@ config RTL8723AE config RTL8188EE tristate "Realtek RTL8188EE Wireless Network Adapter" - depends on RTLWIFI && PCI + depends on PCI + select RTLWIFI + select RTLWIFI_PCI ---help--- This is the driver for Realtek RTL8188EE 802.11n PCIe wireless network adapters. @@ -66,7 +67,9 @@ config RTL8188EE config RTL8192CU tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" - depends on RTLWIFI && USB + depends on USB + select RTLWIFI + select RTLWIFI_USB select RTL8192C_COMMON ---help--- This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB @@ -74,7 +77,28 @@ config RTL8192CU If you choose to build it as a module, it will be called rtl8192cu +config RTLWIFI + tristate + select FW_LOADER + +config RTLWIFI_PCI + tristate + +config RTLWIFI_USB + tristate + +config RTLWIFI_DEBUG + bool "Debugging output for rtlwifi driver family" + depends on RTLWIFI + default y + ---help--- + To use the module option that sets the dynamic-debugging level for, + the front-end driver, this parameter must be "Y". For memory-limited + systems, choose "N". If in doubt, choose "Y". + config RTL8192C_COMMON tristate depends on RTL8192CE || RTL8192CU - default m + default y + +endif diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile index ff02b87..d56f023 100644 --- a/drivers/net/wireless/rtlwifi/Makefile +++ b/drivers/net/wireless/rtlwifi/Makefile @@ -12,13 +12,11 @@ rtlwifi-objs := \ rtl8192c_common-objs += \ -ifneq ($(CONFIG_PCI),) -rtlwifi-objs += pci.o -endif +obj-$(CONFIG_RTLWIFI_PCI) += rtl_pci.o +rtl_pci-objs := pci.o -ifneq ($(CONFIG_USB),) -rtlwifi-objs += usb.o -endif +obj-$(CONFIG_RTLWIFI_USB) += rtl_usb.o +rtl_usb-objs := usb.o obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/ obj-$(CONFIG_RTL8192CE) += rtl8192ce/ diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 9d558ac..7651f5a 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid) { return tid_to_ac[tid]; } +EXPORT_SYMBOL_GPL(rtl_tid_to_ac); static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, struct ieee80211_sta_ht_cap *ht_cap) @@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw) cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); cancel_delayed_work(&rtlpriv->works.fwevt_wq); } +EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work); void rtl_init_rfkill(struct ieee80211_hw *hw) { @@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw) { wiphy_rfkill_stop_polling(hw->wiphy); } +EXPORT_SYMBOL_GPL(rtl_deinit_rfkill); int rtl_init_core(struct ieee80211_hw *hw) { @@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw) return 0; } +EXPORT_SYMBOL_GPL(rtl_init_core); void rtl_deinit_core(struct ieee80211_hw *hw) { } +EXPORT_SYMBOL_GPL(rtl_deinit_core); void rtl_init_rx_config(struct ieee80211_hw *hw) { @@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw) rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); } +EXPORT_SYMBOL_GPL(rtl_init_rx_config); /********************************************************* * @@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) return true; } +EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc); void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, @@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return true; } +EXPORT_SYMBOL_GPL(rtl_action_proc); /*should call before software enc*/ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) @@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) return false; } +EXPORT_SYMBOL_GPL(rtl_is_special_data); /********************************************************* * @@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) rtlpriv->link_info.bcn_rx_inperiod++; } +EXPORT_SYMBOL_GPL(rtl_beacon_statistic); void rtl_watchdog_wq_callback(void *data) { @@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) mac->vendor = vendor; } +EXPORT_SYMBOL_GPL(rtl_recognize_peer); /********************************************************* * @@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = { .name = "rtlsysfs", .attrs = rtl_sysfs_entries, }; +EXPORT_SYMBOL_GPL(rtl_attribute_group); MODULE_AUTHOR("lizhaoming "); MODULE_AUTHOR("Realtek WlanFAE "); @@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core"); -struct rtl_global_var global_var = {}; +struct rtl_global_var rtl_global_var = {}; +EXPORT_SYMBOL_GPL(rtl_global_var); static int __init rtl_core_module_init(void) { @@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void) pr_err("Unable to register rtl_rc, use default RC !!\n"); /* init some global vars */ - INIT_LIST_HEAD(&global_var.glb_priv_list); - spin_lock_init(&global_var.glb_list_lock); + INIT_LIST_HEAD(&rtl_global_var.glb_priv_list); + spin_lock_init(&rtl_global_var.glb_list_lock); return 0; } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 8576bc3..0e5fe09 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); u8 rtl_tid_to_ac(u8 tid); extern struct attribute_group rtl_attribute_group; void rtl_easy_concurrent_retrytimer_callback(unsigned long data); -extern struct rtl_global_var global_var; +extern struct rtl_global_var rtl_global_var; int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, u8 desc_rate, bool first_ampdu); bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index ee84844..733b7ce 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = { .rfkill_poll = rtl_op_rfkill_poll, .flush = rtl_op_flush, }; +EXPORT_SYMBOL_GPL(rtl_ops); diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c index 7d52d3d..76e2086 100644 --- a/drivers/net/wireless/rtlwifi/debug.c +++ b/drivers/net/wireless/rtlwifi/debug.c @@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw) /*Init Debug flag enable condition */ } +EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init); diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 9e38941..838a1ed 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) *pbuf = (u8) (value32 & 0xff); } +EXPORT_SYMBOL_GPL(read_efuse_byte); void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index e70b4ff..703f839 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -35,6 +35,13 @@ #include "efuse.h" #include #include +#include + +MODULE_AUTHOR("lizhaoming "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("PCI basic driver for rtlwifi"); static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { PCI_VENDOR_ID_INTEL, @@ -1886,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev, rtlpriv->rtlhal.interface = INTF_PCI; rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); rtlpriv->intf_ops = &rtl_pci_ops; - rtlpriv->glb_var = &global_var; + rtlpriv->glb_var = &rtl_global_var; /* *init dbgp flags before all diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 71e917d..298b615 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw) spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags); } +EXPORT_SYMBOL_GPL(rtl_ips_nic_on); /*for FW LPS*/ @@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed); } } +EXPORT_SYMBOL_GPL(rtl_swlps_beacon); void rtl_swlps_rf_awake(struct ieee80211_hw *hw) { @@ -623,6 +625,7 @@ void rtl_lps_change_work_callback(struct work_struct *work) else rtl_lps_leave(hw); } +EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); void rtl_swlps_wq_callback(void *data) { @@ -934,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) else rtl_p2p_noa_ie(hw, data, len - FCS_LEN); } +EXPORT_SYMBOL_GPL(rtl_p2p_info); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 1feebdc..e56778c 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -32,6 +32,13 @@ #include "ps.h" #include "rtl8192c/fw_common.h" #include +#include + +MODULE_AUTHOR("lizhaoming "); +MODULE_AUTHOR("Realtek WlanFAE "); +MODULE_AUTHOR("Larry Finger "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("USB basic driver for rtlwifi"); #define REALTEK_USB_VENQT_READ 0xC0 #define REALTEK_USB_VENQT_WRITE 0x40 -- cgit v0.10.2 From 64b6f46f1141ad938e354f37af62e28da972e8eb Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Jul 2013 11:03:57 +0530 Subject: ath9k_hw: Fix multicast search for AR9002 family The multicast search bit is disabled for the AR9003 family, but this is required for AR9002 too. Fix this in the INI override routine. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index d1acfe9..1576d58 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); if (AR_SREV_9280_20_OR_LATER(ah)) { - val = REG_READ(ah, AR_PCU_MISC_MODE2); + /* + * For AR9280 and above, there is a new feature that allows + * Multicast search based on both MAC Address and Key ID. + * By default, this feature is enabled. But since the driver + * is not using this feature, we switch it off; otherwise + * multicast search based on MAC addr only will fail. + */ + val = REG_READ(ah, AR_PCU_MISC_MODE2) & + (~AR_ADHOC_MCAST_KEYID_ENABLE); if (!AR_SREV_9271(ah)) val &= ~AR_PCU_MISC_MODE2_HWWAR1; -- cgit v0.10.2 From 233a26e85f9a72bcd0cdb7a95d1d5abcd052369f Mon Sep 17 00:00:00 2001 From: Maximilian Schneider Date: Tue, 2 Jul 2013 23:43:29 +0000 Subject: net: can: esd_usb2: check index of array before accessing The esd_usb2_read_bulk_callback() function is parsing the data that comes from the USB CAN adapter. One datum is used as an index to access the dev->nets[] array. This patch adds the missing bounds checking. Acked-by: Matthias Fuchs Signed-off-by: Maximilian Schneider Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 6aa7b32..ac6177d 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb) switch (msg->msg.hdr.cmd) { case CMD_CAN_RX: + if (msg->msg.rx.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg); break; case CMD_CAN_TX: + if (msg->msg.txdone.net >= dev->net_count) { + dev_err(dev->udev->dev.parent, "format error\n"); + break; + } + esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net], msg); break; -- cgit v0.10.2 From 7671986839f9207f8d76e8ef92b2d3f263a794cc Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Thu, 18 Jul 2013 01:20:33 +0400 Subject: can: usb_8dev: fix urb leak on failure path in usb_8dev_start() If usb_8dev_start() fails to submit urb, it unanchors the urb but forgets to free it. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index cbd388e..8becd3d 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv) usb_unanchor_urb(urb); usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma); + usb_free_urb(urb); break; } -- cgit v0.10.2 From 7427b370e0aa6226c763af94fc5c4e3433383543 Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Thu, 20 Jun 2013 11:11:04 +0200 Subject: NFC: Fix NCI over SPI build kbuild test robot found following error: net/built-in.o: In function `nci_spi_send': >> spi.c:(.text+0x19a76f): undefined reference to `crc_ccitt' Add CRC_CCITT module to Kconfig to fix it Reported-by: kbuild test robot. Signed-off-by: Frederic Danis Signed-off-by: Samuel Ortiz diff --git a/net/nfc/nci/Kconfig b/net/nfc/nci/Kconfig index 2a24160..a4f1e42 100644 --- a/net/nfc/nci/Kconfig +++ b/net/nfc/nci/Kconfig @@ -11,6 +11,7 @@ config NFC_NCI config NFC_NCI_SPI depends on NFC_NCI && SPI + select CRC_CCITT bool "NCI over SPI protocol support" default n help -- cgit v0.10.2 From 372675a4a9ac0a0af962d44dadeea69926ce45e0 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 18 Jul 2013 08:38:26 -0700 Subject: vxlan: unregister on namespace exit Fix memory leaks and other badness from VXLAN network namespace teardown. When network namespace is removed, all the vxlan devices should be unregistered (not closed). Signed-off-by: Stephen Hemminger Reviewed-by: Pravin B Shelar Signed-off-by: David S. Miller diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a5ba8dd..f101034 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1878,10 +1878,12 @@ static __net_exit void vxlan_exit_net(struct net *net) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_dev *vxlan; + LIST_HEAD(list); rtnl_lock(); list_for_each_entry(vxlan, &vn->vxlan_list, next) - dev_close(vxlan->dev); + unregister_netdevice_queue(vxlan->dev, &list); + unregister_netdevice_many(&list); rtnl_unlock(); } -- cgit v0.10.2 From 3fc2de2faba387218bdf9dbc6b13f513ac3b060a Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 18 Jul 2013 08:40:15 -0700 Subject: vxlan: fix igmp races There are two race conditions in existing code for doing IGMP management in workqueue in vxlan. First, the vxlan_group_used function checks the list of vxlan's without any protection, and it is possible for open followed by close to occur before the igmp work queue runs. To solve these move the check into vxlan_open/stop so it is protected by RTNL. And split into two work structures so that there is no racy reference to underlying device state. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f101034..f4c6db4 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -136,7 +136,8 @@ struct vxlan_dev { u32 flags; /* VXLAN_F_* below */ struct work_struct sock_work; - struct work_struct igmp_work; + struct work_struct igmp_join; + struct work_struct igmp_leave; unsigned long age_interval; struct timer_list age_timer; @@ -736,7 +737,6 @@ static bool vxlan_snoop(struct net_device *dev, return false; } - /* See if multicast group is already in use by other ID */ static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip) { @@ -770,12 +770,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs) queue_work(vxlan_wq, &vs->del_work); } -/* Callback to update multicast group membership. - * Scheduled when vxlan goes up/down. +/* Callback to update multicast group membership when first VNI on + * multicast asddress is brought up + * Done as workqueue because ip_mc_join_group acquires RTNL. */ -static void vxlan_igmp_work(struct work_struct *work) +static void vxlan_igmp_join(struct work_struct *work) { - struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work); + struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join); struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); struct vxlan_sock *vs = vxlan->vn_sock; struct sock *sk = vs->sock->sk; @@ -785,10 +786,27 @@ static void vxlan_igmp_work(struct work_struct *work) }; lock_sock(sk); - if (vxlan_group_used(vn, vxlan->default_dst.remote_ip)) - ip_mc_join_group(sk, &mreq); - else - ip_mc_leave_group(sk, &mreq); + ip_mc_join_group(sk, &mreq); + release_sock(sk); + + vxlan_sock_release(vn, vs); + dev_put(vxlan->dev); +} + +/* Inverse of vxlan_igmp_join when last VNI is brought down */ +static void vxlan_igmp_leave(struct work_struct *work) +{ + struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave); + struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id); + struct vxlan_sock *vs = vxlan->vn_sock; + struct sock *sk = vs->sock->sk; + struct ip_mreqn mreq = { + .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip, + .imr_ifindex = vxlan->default_dst.remote_ifindex, + }; + + lock_sock(sk); + ip_mc_leave_group(sk, &mreq); release_sock(sk); vxlan_sock_release(vn, vs); @@ -1359,6 +1377,7 @@ static void vxlan_uninit(struct net_device *dev) /* Start ageing timer and join group when device is brought up */ static int vxlan_open(struct net_device *dev) { + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_sock *vs = vxlan->vn_sock; @@ -1366,10 +1385,11 @@ static int vxlan_open(struct net_device *dev) if (!vs) return -ENOTCONN; - if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { + if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && + ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); - queue_work(vxlan_wq, &vxlan->igmp_work); + queue_work(vxlan_wq, &vxlan->igmp_join); } if (vxlan->age_interval) @@ -1400,13 +1420,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan) /* Cleanup timer and forwarding table on shutdown */ static int vxlan_stop(struct net_device *dev) { + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_sock *vs = vxlan->vn_sock; - if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) { + if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && + ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); - queue_work(vxlan_wq, &vxlan->igmp_work); + queue_work(vxlan_wq, &vxlan->igmp_leave); } del_timer_sync(&vxlan->age_timer); @@ -1471,7 +1493,8 @@ static void vxlan_setup(struct net_device *dev) INIT_LIST_HEAD(&vxlan->next); spin_lock_init(&vxlan->hash_lock); - INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work); + INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join); + INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave); INIT_WORK(&vxlan->sock_work, vxlan_sock_work); init_timer_deferrable(&vxlan->age_timer); -- cgit v0.10.2 From 2deb535af7c824f37d6bc8657fd09e3d10696ee8 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 19 Jul 2013 16:56:26 -0400 Subject: qlcnic: Fix invalid register offset calculation 83xx adapter specific code was accessing 82xx register which resulted in invalid register offset. This patch uses proper register access method. Signed-off-by: Shahed Shaikh Signed-off-by: Jitendra Kalsaria Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 700a463..05a847e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1540,7 +1540,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) return 0; case QLCNIC_SET_QUIESCENT: case QLCNIC_RESET_QUIESCENT: - state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); + state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE); if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) netdev_info(netdev, "Device in FAILED state\n"); return 0; -- cgit v0.10.2 From cfacb172fa699263a4f74a63d886e171fe3eafbe Mon Sep 17 00:00:00 2001 From: Pratik Pujar Date: Fri, 19 Jul 2013 16:56:27 -0400 Subject: qlcnic: Set __QLCNIC_DEV_UP in adapter state before enabling interrupts NAPI poll function does not re-enable the interrupt, if __QLCNIC_DEV_UP is not set in adapter state. This was preventing driver from receiving any packet. Signed-off-by: Pratik Pujar Signed-off-by: Jitendra Kalsaria Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 4528f8e..41635f2 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -1531,12 +1531,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev) if (netdev->features & NETIF_F_LRO) qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED); + set_bit(__QLCNIC_DEV_UP, &adapter->state); qlcnic_napi_enable(adapter); qlcnic_linkevent_request(adapter, 1); adapter->ahw->reset_context = 0; - set_bit(__QLCNIC_DEV_UP, &adapter->state); return 0; } -- cgit v0.10.2 From e9a355a9b407da41b7cb22767f3898d4628411b2 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Fri, 19 Jul 2013 16:56:28 -0400 Subject: qlcnic: Fix NULL pointer dereference in VF probe path. o Check for non-NULL set_mac_filter_count function pointer before calling it fixes the panic. This patch fixes regression introduced by patch "qlcnic: Secondary unicast MAC address support." with commit id 168e4fb54c11865668ad50eff81b5f2729e0e0f4. Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index b00cf56..f4bb8f5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1869,7 +1869,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter) { - adapter->ahw->hw_ops->set_mac_filter_count(adapter); + if (adapter->ahw->hw_ops->set_mac_filter_count) + adapter->ahw->hw_ops->set_mac_filter_count(adapter); } static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, -- cgit v0.10.2 From 8dc394af2e6159d3799b1219625db47c42a1964f Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Fri, 19 Jul 2013 16:56:29 -0400 Subject: qlcnic: Fix multicast packet handling for PF and VF. o Multicast MAC was not getting programmed due to which multicast packets were being dropped by FW. This patch fixes commit 168e4fb54c11865668ad50eff81b5f2729e0e0f4 ("qlcnic: Secondary unicast MAC address support.") which introduced bug in handling multicast packets. Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 5b5d2ed..4ed7e73 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -516,20 +516,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) if (netdev->flags & IFF_PROMISC) { if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) mode = VPORT_MISS_MODE_ACCEPT_ALL; - } else if (netdev->flags & IFF_ALLMULTI) { - if (netdev_mc_count(netdev) > ahw->max_mc_count) { - mode = VPORT_MISS_MODE_ACCEPT_MULTI; - } else if (!netdev_mc_empty(netdev) && - !qlcnic_sriov_vf_check(adapter)) { - netdev_for_each_mc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, - vlan); - } - if (mode != VPORT_MISS_MODE_ACCEPT_MULTI && - qlcnic_sriov_vf_check(adapter)) - qlcnic_vf_add_mc_list(netdev, vlan); + } else if ((netdev->flags & IFF_ALLMULTI) || + (netdev_mc_count(netdev) > ahw->max_mc_count)) { + mode = VPORT_MISS_MODE_ACCEPT_MULTI; + } else if (!netdev_mc_empty(netdev) && + !qlcnic_sriov_vf_check(adapter)) { + netdev_for_each_mc_addr(ha, netdev) + qlcnic_nic_add_mac(adapter, ha->addr, vlan); } + if (qlcnic_sriov_vf_check(adapter)) + qlcnic_vf_add_mc_list(netdev, vlan); + /* configure unicast MAC address, if there is not sufficient space * to store all the unicast addresses then enable promiscuous mode */ -- cgit v0.10.2 From cab150b5874babb0a3d558c10d28c936fdf6ac69 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Fri, 19 Jul 2013 16:56:30 -0400 Subject: qlcnic: Fix panic while setting VF's MAC address o "qlcnic_sriov" structure pointer should be accessed only when SR-IOV is enabled. Access this pointer after SR-IOV PF check. Signed-off-by: Manish Chopra Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index ee0c1d3..b9b88f3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -1621,13 +1621,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_sriov *sriov = adapter->ahw->sriov; - int i, num_vfs = sriov->num_vfs; + int i, num_vfs; struct qlcnic_vf_info *vf_info; u8 *curr_mac; if (!qlcnic_sriov_pf_check(adapter)) return -EOPNOTSUPP; + num_vfs = sriov->num_vfs; + if (!is_valid_ether_addr(mac) || vf >= num_vfs) return -EINVAL; -- cgit v0.10.2 From 15d79747b57159fc1e063f1404e4f379cb5be026 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 19 Jul 2013 16:56:31 -0400 Subject: qlcnic: Fix ethtool display for 83xx adapter. o Commit b938662d88264c1a92611ca1b82fdff5a4e87121 ("qlcnic: Fix ethtool supported port status for 83xx") introduced regression for display of link status for 83xx adapter while refactoring port status display. This patch is to fix the link status display for 83xx adapter. Signed-off-by: Himanshu Madhani Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 0913c62..bc483e1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3014,8 +3014,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter, } if (ahw->port_type == QLCNIC_XGBE) { - ecmd->supported = SUPPORTED_1000baseT_Full; - ecmd->advertising = ADVERTISED_1000baseT_Full; + ecmd->supported = SUPPORTED_10000baseT_Full; + ecmd->advertising = ADVERTISED_10000baseT_Full; } else { ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | -- cgit v0.10.2 From 744b66dde0dcdf3a0c31e1f6540d1f59d779ddd0 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 19 Jul 2013 16:56:32 -0400 Subject: qlcnic: Fix dump template version mask Driver was using wrong mask for template version. Signed-off-by: Shahed Shaikh Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index ab8a674..79e54ef 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1084,7 +1084,7 @@ flash_temp: tmpl_hdr = ahw->fw_dump.tmpl_hdr; tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF; - if ((tmpl_hdr->version & 0xffffff) >= 0x20001) + if ((tmpl_hdr->version & 0xfffff) >= 0x20001) ahw->fw_dump.use_pex_dma = true; else ahw->fw_dump.use_pex_dma = false; -- cgit v0.10.2 From b662eca098184184a4d9df09835c3740401fb6a0 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Fri, 19 Jul 2013 16:56:33 -0400 Subject: qlcnic: Fix releasing of Tx frag which was never mapped. o Driver was freeing Tx frag which was never mapped before which result into panic as kernel was unable to handle paging request. BUG: unable to handle kernel paging request at ffffc9002552a000 IP: [] qlcnic_release_tx_buffers+0x72/0x170 [qlcnic] PGD 87fc15067 PUD 47febf067 PMD 4758c5067 PTE 0 Oops: 0000 [#1] SMP crash> bt PID: 27343 TASK: ffff8802a5de8080 CPU: 27 COMMAND: "ifconfig" [ffff8802a34b3850] machine_kexec at ffffffff81035b7b [ffff8802a34b38b0] crash_kexec at ffffffff810c0db2 [ffff8802a34b3980] oops_end at ffffffff815111d0 [ffff8802a34b39b0] no_context at ffffffff81046bfb [ffff8802a34b3a00] __bad_area_nosemaphore at ffffffff81046e85 [ffff8802a34b3a50] bad_area_nosemaphore at ffffffff81046f53 [ffff8802a34b3a60] __do_page_fault at ffffffff810476b1 [ffff8802a34b3b80] do_page_fault at ffffffff8151311e [ffff8802a34b3bb0] page_fault at ffffffff815104d5 [exception RIP: qlcnic_release_tx_buffers+114] RIP: ffffffffa05ed762 RSP: ffff8802a34b3c68 RFLAGS: 00010246 RAX: ffff88087989c000 RBX: ffffc90025529ff8 RCX: 0000000000000001 RDX: 0000000000000013 RSI: 0000000000000013 RDI: 0000000000000000 RBP: ffff8802a34b3ca8 R8: 0000000000000000 R9: 0000000000000000 R10: 000000000000000c R11: 0000000000000000 R12: 0000000000000012 R13: ffffc90025529ec0 R14: ffff880761e876e0 R15: 00000000000003ff ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 [ffff8802a34b3cb0] __qlcnic_down at ffffffffa05e8b15 [qlcnic] [ffff8802a34b3d00] qlcnic_close at ffffffffa05e8b78 [qlcnic] [ffff8802a34b3d10] dev_close at ffffffff81449d81 [ffff8802a34b3d30] dev_change_flags at ffffffff814495c1 Signed-off-by: Jitendra Kalsaria Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c index d28336f..a202309 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c @@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter) buffrag->length, PCI_DMA_TODEVICE); buffrag->dma = 0ULL; } - for (j = 0; j < cmd_buf->frag_count; j++) { + for (j = 1; j < cmd_buf->frag_count; j++) { buffrag++; if (buffrag->dma) { pci_unmap_page(adapter->pdev, buffrag->dma, -- cgit v0.10.2 From 2f0a9afaefcedfdb803e1347b0fe429cbd84d525 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Fri, 19 Jul 2013 16:56:34 -0400 Subject: qlcnic: Fix guest VLAN o Clear cached vport vlan variable(vp->vlan) in PF on PCI FLR and back-channel termination which will allow to configure guest VLAN on VF after force off/shut down the guest VM. Signed-off-by: Manish Chopra Signed-off-by: Sucheta Chakraborty Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index b9b88f3..46aeb59 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -635,10 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, struct qlcnic_cmd_args *cmd) { struct qlcnic_vf_info *vf = trans->vf; - struct qlcnic_adapter *adapter = vf->adapter; - int err; + struct qlcnic_vport *vp = vf->vp; + struct qlcnic_adapter *adapter; u16 func = vf->pci_func; + int err; + adapter = vf->adapter; cmd->rsp.arg[0] = trans->req_hdr->cmd_op; cmd->rsp.arg[0] |= (1 << 16); @@ -650,6 +652,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, qlcnic_sriov_pf_config_vport(adapter, 0, func); } } else { + if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) + vp->vlan = 0; err = qlcnic_sriov_pf_config_vport(adapter, 0, func); } @@ -1561,6 +1565,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, struct qlcnic_vf_info *vf) { struct net_device *dev = vf->adapter->netdev; + struct qlcnic_vport *vp = vf->vp; if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) { clear_bit(QLC_BC_VF_FLR, &vf->state); @@ -1573,6 +1578,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov, return; } + if (vp->vlan_mode == QLC_GUEST_VLAN_MODE) + vp->vlan = 0; + qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr); netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func); } -- cgit v0.10.2 From b69bbddfa136dc53ac319d58bc38b41f8aefffea Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Thu, 18 Jul 2013 16:15:11 -0300 Subject: veth: add vlan features The veth device doesn't provide the vlan features, so TSO for example is disabled and that causes performance issues when using tagged traffic. The test topology looks like this: br0 br1 / \ / \ vnet veth0.10 ----- veth1.10 vnet VM VM The netperf results with current veth driver: MIGRATED TCP STREAM TEST from 192.168.1.1 () port 0 AF_INET to 192.168.1.2 () port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 10.01 2210.22 Now after applying the proposed patch: MIGRATED TCP STREAM TEST from 192.168.1.1 () port 0 AF_INET to 192.168.1.2 () port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 10.00 13067.47 Signed-off-by: Flavio Leitner Signed-off-by: David S. Miller diff --git a/drivers/net/veth.c b/drivers/net/veth.c index da86652..eee1f19 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->features |= VETH_FEATURES; + dev->vlan_features = dev->features; dev->destructor = veth_dev_free; dev->hw_features = VETH_FEATURES; -- cgit v0.10.2 From 087d273caf4f7d3f2159256f255f1f432bc84a5b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 19 Jul 2013 08:48:05 +0300 Subject: arcnet: cleanup sizeof parameter This patch doesn't change the compiled code because ARC_HDR_SIZE is 4 and sizeof(int) is 4, but the intent was to use the header size and not the sizeof the header size. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index a746ba2..a956053 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum) soft = &pkt.soft.rfc1201; - lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE)); + lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE); if (pkt.hard.offset[0]) { ofs = pkt.hard.offset[0]; length = 256 - ofs; -- cgit v0.10.2 From 651e92716aaae60fc41b9652f54cb6803896e0da Mon Sep 17 00:00:00 2001 From: Michal Tesar Date: Fri, 19 Jul 2013 14:09:01 +0200 Subject: sysctl net: Keep tcp_syn_retries inside the boundary Limit the min/max value passed to the /proc/sys/net/ipv4/tcp_syn_retries. Signed-off-by: Michal Tesar Signed-off-by: David S. Miller diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index b2c123c..610e324 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -36,6 +36,8 @@ static int tcp_adv_win_scale_min = -31; static int tcp_adv_win_scale_max = 31; static int ip_ttl_min = 1; static int ip_ttl_max = 255; +static int tcp_syn_retries_min = 1; +static int tcp_syn_retries_max = MAX_TCP_SYNCNT; static int ip_ping_group_range_min[] = { 0, 0 }; static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; @@ -332,7 +334,9 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_syn_retries, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .proc_handler = proc_dointvec_minmax, + .extra1 = &tcp_syn_retries_min, + .extra2 = &tcp_syn_retries_max }, { .procname = "tcp_synack_retries", -- cgit v0.10.2 From 1faabf2aab1fdaa1ace4e8c829d1b9cf7bfec2f1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 19 Jul 2013 20:07:16 -0700 Subject: bridge: do not call setup_timer() multiple times commit 9f00b2e7cf24 ("bridge: only expire the mdb entry when query is received") added a nasty bug as an active timer can be reinitialized. setup_timer() must be done once, no matter how many time mod_timer() is called. br_multicast_new_group() is the right place to do this. Reported-by: Srivatsa S. Bhat Diagnosed-by: Thomas Gleixner Signed-off-by: Eric Dumazet Tested-by: Srivatsa S. Bhat Cc: Cong Wang Signed-off-by: David S. Miller diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 69af490..4b99c9a 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -619,6 +619,9 @@ rehash: mp->br = br; mp->addr = *group; + setup_timer(&mp->timer, br_multicast_group_expired, + (unsigned long)mp); + hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); mdb->size++; @@ -1126,7 +1129,6 @@ static int br_ip4_multicast_query(struct net_bridge *br, if (!mp) goto out; - setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp); mod_timer(&mp->timer, now + br->multicast_membership_interval); mp->timer_armed = true; @@ -1204,7 +1206,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, if (!mp) goto out; - setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp); mod_timer(&mp->timer, now + br->multicast_membership_interval); mp->timer_armed = true; -- cgit v0.10.2 From 07b155031fb32b3c6ab7f9933a9c280146e4a7b2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Jul 2013 23:03:36 +0200 Subject: ath10k: ATH10K should depend on HAS_DMA If NO_DMA=y: drivers/built-in.o: In function `ath10k_skb_unmap': drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' drivers/built-in.o: In function `ath10k_skb_map': drivers/net/wireless/ath/ath10k/core.h:83: undefined reference to `dma_map_single' drivers/net/wireless/ath/ath10k/core.h:86: undefined reference to `dma_mapping_error' drivers/built-in.o: In function `ath10k_htt_rx_ring_free': drivers/net/wireless/ath/ath10k/htt_rx.c:113: undefined reference to `dma_unmap_single' drivers/built-in.o: In function `ath10k_htt_rx_amsdu_pop': drivers/net/wireless/ath/ath10k/htt_rx.c:296: undefined reference to `dma_unmap_single' drivers/net/wireless/ath/ath10k/htt_rx.c:389: undefined reference to `dma_unmap_single' drivers/built-in.o: In function `__ath10k_htt_rx_ring_fill_n': drivers/net/wireless/ath/ath10k/htt_rx.c:146: undefined reference to `dma_map_single' drivers/net/wireless/ath/ath10k/htt_rx.c:150: undefined reference to `dma_mapping_error' drivers/built-in.o: In function `ath10k_htt_rx_attach': drivers/net/wireless/ath/ath10k/htt_rx.c:474: undefined reference to `dma_alloc_coherent' drivers/net/wireless/ath/ath10k/htt_rx.c:509: undefined reference to `dma_free_coherent' drivers/net/wireless/ath/ath10k/htt_rx.c:514: undefined reference to `dma_free_coherent' drivers/built-in.o: In function `ath10k_htt_rx_detach': drivers/net/wireless/ath/ath10k/htt_rx.c:220: undefined reference to `dma_unmap_single' drivers/net/wireless/ath/ath10k/htt_rx.c:228: undefined reference to `dma_free_coherent' drivers/built-in.o: In function `ath10k_skb_map': drivers/net/wireless/ath/ath10k/core.h:83: undefined reference to `dma_map_single' drivers/net/wireless/ath/ath10k/core.h:86: undefined reference to `dma_mapping_error' drivers/built-in.o: In function `ath10k_skb_unmap': drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' drivers/built-in.o: In function `ath10k_skb_map': drivers/net/wireless/ath/ath10k/core.h:83: undefined reference to `dma_map_single' drivers/net/wireless/ath/ath10k/core.h:86: undefined reference to `dma_mapping_error' drivers/net/wireless/ath/ath10k/core.h:83: undefined reference to `dma_map_single' drivers/net/wireless/ath/ath10k/core.h:86: undefined reference to `dma_mapping_error' drivers/built-in.o: In function `ath10k_skb_unmap': drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' drivers/net/wireless/ath/ath10k/core.h:98: undefined reference to `dma_unmap_single' Signed-off-by: Geert Uytterhoeven Cc: linux-wireless@vger.kernel.org Signed-off-by: Kalle Valo diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index cde58fe..82e8088 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -1,6 +1,6 @@ config ATH10K tristate "Atheros 802.11ac wireless cards support" - depends on MAC80211 + depends on MAC80211 && HAS_DMA select ATH_COMMON ---help--- This module adds support for wireless adapters based on -- cgit v0.10.2 From 2ea0ffcbc0993d5c41b47f6cec858fd178fb09ac Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 22 Jul 2013 12:22:19 +0300 Subject: MAINTAINERS: add ath10k I forgot to add an entry to MAINTAINERS when submitting the driver. Signed-off-by: Kalle Valo diff --git a/MAINTAINERS b/MAINTAINERS index bf61e04..44626b8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6719,6 +6719,14 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/tuners/qt1010* +QUALCOMM ATHEROS ATH10K WIRELESS DRIVER +M: Kalle Valo +L: ath10k@lists.infradead.org +W: http://wireless.kernel.org/en/users/Drivers/ath10k +T: git git://github.com/kvalo/ath.git +S: Supported +F: drivers/net/wireless/ath/ath10k/ + QUALCOMM HEXAGON ARCHITECTURE M: Richard Kuo L: linux-hexagon@vger.kernel.org -- cgit v0.10.2 From 27abb2ffb07a70bdebf9a785658f68f10600281c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Jul 2013 08:34:59 +0800 Subject: pch_dma: fix error return code in pch_dma_probe() Fix to return -ENODEV when no proper base address found error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Vinod Koul diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index ce3dc3e..0bbdea5 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -867,6 +867,7 @@ static int pch_dma_probe(struct pci_dev *pdev, if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "Cannot find proper base address\n"); + err = -ENODEV; goto err_disable_pdev; } -- cgit v0.10.2 From 58cfb681bffb43654776a218a087028ff425ba9e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Mon, 22 Jul 2013 12:26:12 +0300 Subject: MAINTAINERS: update ath6kl git location The git tree is in github.com nowadays. Signed-off-by: Kalle Valo diff --git a/MAINTAINERS b/MAINTAINERS index 44626b8..7a403ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1406,7 +1406,7 @@ ATHEROS ATH6KL WIRELESS DRIVER M: Kalle Valo L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/en/users/Drivers/ath6kl -T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath6kl.git +T: git git://github.com/kvalo/ath.git S: Supported F: drivers/net/wireless/ath/ath6kl/ -- cgit v0.10.2 From b6992fa9a74862c5addb62cde1657c7479615d86 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 17 Jul 2013 17:54:27 +0100 Subject: ARM: document DEBUG_UNCOMPRESS Kconfig option This non-user visible option lacked any kind of documentation. This is quite common for non-user visible options; certian people can't understand the point of documenting such options with help text. However, here we have a case in point: developers don't understand the option either, as they were thinking that when the option is not set, the decompressor should produce no output what so ever. This is incorrect, as the purpose of this option is to control whether a multiplatform kernel uses the kernel debugging macros to produce output or not. So let's document this via help rather than commentry to prevent others falling into this misunderstanding. Signed-off-by: Russell King diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index e401a76..583f4a0 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -804,9 +804,19 @@ config DEBUG_LL_INCLUDE config DEBUG_UNCOMPRESS bool - default y if ARCH_MULTIPLATFORM && DEBUG_LL && \ - !DEBUG_OMAP2PLUS_UART && \ + depends on ARCH_MULTIPLATFORM + default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \ !DEBUG_TEGRA_UART + help + This option influences the normal decompressor output for + multiplatform kernels. Normally, multiplatform kernels disable + decompressor output because it is not possible to know where to + send the decompressor output. + + When this option is set, the selected DEBUG_LL output method + will be re-used for normal decompressor output on multiplatform + kernels. + config UNCOMPRESS_INCLUDE string -- cgit v0.10.2 From bf3f0f332f76a85ff3a0b393aaded5a8533769c0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 15 Jul 2013 14:26:19 +0100 Subject: ARM: 7784/1: mm: ensure SMP alternates assemble to exactly 4 bytes with Thumb-2 Commit ae8a8b9553bd ("ARM: 7691/1: mm: kill unused TLB_CAN_READ_FROM_L1_CACHE and use ALT_SMP instead") added early function returns for page table cache flushing operations on ARMv7 SMP CPUs. Unfortunately, when targetting Thumb-2, these `mov pc, lr' sequences assemble to 2 bytes which can lead to corruption of the instruction stream after code patching. This patch fixes the alternates to use wide (32-bit) instructions for Thumb-2, therefore ensuring that the patching code works correctly. Cc: Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index f64afb9..bdd3be4 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S @@ -110,7 +110,7 @@ ENTRY(cpu_v7_set_pte_ext) ARM( str r3, [r0, #2048]! ) THUMB( add r0, r0, #2048 ) THUMB( str r3, [r0] ) - ALT_SMP(mov pc,lr) + ALT_SMP(W(nop)) ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte #endif mov pc, lr diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index c36ac69..01a719e 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -81,7 +81,7 @@ ENTRY(cpu_v7_set_pte_ext) tst r3, #1 << (55 - 32) @ L_PTE_DIRTY orreq r2, #L_PTE_RDONLY 1: strd r2, r3, [r0] - ALT_SMP(mov pc, lr) + ALT_SMP(W(nop)) ALT_UP (mcr p15, 0, r0, c7, c10, 1) @ flush_pte #endif mov pc, lr diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 5c6d5a3..73398bc 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -75,13 +75,14 @@ ENTRY(cpu_v7_do_idle) ENDPROC(cpu_v7_do_idle) ENTRY(cpu_v7_dcache_clean_area) - ALT_SMP(mov pc, lr) @ MP extensions imply L1 PTW - ALT_UP(W(nop)) - dcache_line_size r2, r3 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + ALT_SMP(W(nop)) @ MP extensions imply L1 PTW + ALT_UP_B(1f) + mov pc, lr +1: dcache_line_size r2, r3 +2: mcr p15, 0, r0, c7, c10, 1 @ clean D entry add r0, r0, r2 subs r1, r1, r2 - bhi 1b + bhi 2b dsb mov pc, lr ENDPROC(cpu_v7_dcache_clean_area) -- cgit v0.10.2 From c65b7e98b4edce7faf534154b28eae8fb579144b Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 17 Jul 2013 17:53:04 +0100 Subject: ARM: 7785/1: mm: restrict early_alloc to section-aligned memory When map_lowmem() runs, and processes a memory bank whose start or end is not section-aligned, memory must be allocated to store the 2nd-level page tables. Those allocations are made by calling memblock_alloc(). At this point, the only memory that is free *and* mapped is memory which has already been mapped by map_lowmem() itself. For this reason, we must calculate the first point at which map_lowmem() will need to allocate memory, and set the memblock allocation limit to a lower address, so that memblock_alloc() is guaranteed to return memory that is already mapped. This patch enhances sanity_check_meminfo() to calculate that memory address, and pass it to memblock_set_current_limit(), rather than just assuming the limit is arm_lowmem_limit. The algorithm applied is: * Default memblock_limit to arm_lowmem_limit in the absence of any other limit; arm_lowmem_limit is the highest memory that is mapped by map_lowmem(). * While walking the list of memblocks, if the start of a block is not aligned, 2nd-level page tables will need to be allocated to map the first few pages of the block. Hence, the memblock_limit must be before the start of the block. * Similarly, if the end of any block is not aligned, 2nd-level page tables will need to be allocated to map the last few pages of the block. Hence, the memblock_limit must point at the end of the block, rounded down to section-alignment. * The memory blocks are assumed to be sorted in address order, so the first unaligned block start or end is used to set the limit. With this algorithm, the start or end of almost any bank can be non- section-aligned. The only exception is that the start of bank 0 must be section-aligned, since otherwise memory would need to be allocated when mapping the start of bank 0, which occurs before any free memory is mapped. [swarren, wrote commit description, rewrote calculation of memblock_limit] Signed-off-by: Stephen Warren Signed-off-by: Russell King diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4f56617..b3fdb63 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -989,6 +989,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0; void __init sanity_check_meminfo(void) { + phys_addr_t memblock_limit = 0; int i, j, highmem = 0; phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; @@ -1052,9 +1053,32 @@ void __init sanity_check_meminfo(void) bank->size = size_limit; } #endif - if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit) - arm_lowmem_limit = bank->start + bank->size; + if (!bank->highmem) { + phys_addr_t bank_end = bank->start + bank->size; + if (bank_end > arm_lowmem_limit) + arm_lowmem_limit = bank_end; + + /* + * Find the first non-section-aligned page, and point + * memblock_limit at it. This relies on rounding the + * limit down to be section-aligned, which happens at + * the end of this function. + * + * With this algorithm, the start or end of almost any + * bank can be non-section-aligned. The only exception + * is that the start of the bank 0 must be section- + * aligned, since otherwise memory would need to be + * allocated when mapping the start of bank 0, which + * occurs before any free memory is mapped. + */ + if (!memblock_limit) { + if (!IS_ALIGNED(bank->start, SECTION_SIZE)) + memblock_limit = bank->start; + else if (!IS_ALIGNED(bank_end, SECTION_SIZE)) + memblock_limit = bank_end; + } + } j++; } #ifdef CONFIG_HIGHMEM @@ -1079,7 +1103,18 @@ void __init sanity_check_meminfo(void) #endif meminfo.nr_banks = j; high_memory = __va(arm_lowmem_limit - 1) + 1; - memblock_set_current_limit(arm_lowmem_limit); + + /* + * Round the memblock limit down to a section size. This + * helps to ensure that we will allocate memory from the + * last full section, which should be mapped. + */ + if (memblock_limit) + memblock_limit = round_down(memblock_limit, SECTION_SIZE); + if (!memblock_limit) + memblock_limit = arm_lowmem_limit; + + memblock_set_current_limit(memblock_limit); } static inline void prepare_page_table(void) @@ -1276,8 +1311,6 @@ void __init paging_init(struct machine_desc *mdesc) { void *zero_page; - memblock_set_current_limit(arm_lowmem_limit); - build_mem_type_table(); prepare_page_table(); map_lowmem(); -- cgit v0.10.2 From b60d5db690f72a7cfe5e39f191f0719a9ef3a096 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 18 Jul 2013 17:20:32 +0100 Subject: ARM: 7786/1: hyp: fix macro parameterisation Currently, compare_cpu_mode_with_primary uses a mixture of macro arguments and hardcoded registers, and does so incorrectly, as it stores (__boot_cpu_mode_offset | BOOT_CPU_MODE_MISMATCH) to (__boot_cpu_mode + &__boot_cpu_mode_offset), which could corrupt an arbitrary portion of memory. This patch fixes up compare_cpu_mode_with_primary to use the macro arguments, correctly updating __boot_cpu_mode. Signed-off-by: Mark Rutland Acked-by: Dave Martin Acked-by: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Russell King diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S index 4910232..797b1a6 100644 --- a/arch/arm/kernel/hyp-stub.S +++ b/arch/arm/kernel/hyp-stub.S @@ -56,8 +56,8 @@ ENTRY(__boot_cpu_mode) ldr \reg3, [\reg2] ldr \reg1, [\reg2, \reg3] cmp \mode, \reg1 @ matches primary CPU boot mode? - orrne r7, r7, #BOOT_CPU_MODE_MISMATCH - strne r7, [r5, r6] @ record what happened and give up + orrne \reg1, \reg1, #BOOT_CPU_MODE_MISMATCH + strne \reg1, [\reg2, \reg3] @ record what happened and give up .endm #else /* ZIMAGE */ -- cgit v0.10.2 From 40d18ff959fe8b847be4f7b03f84644a7c18211e Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Fri, 19 Jul 2013 17:37:39 +0800 Subject: mac80211: prevent the buffering or frame transmission to non-assoc mesh STA This patch is intended to avoid the buffering to non-assoc mesh STA and also to avoid the triggering of frame to non-assoc mesh STA which could cause kernel panic in specific hw. One of the examples, is kernel panic happens to ath9k if user space inserts the mesh STA and not proceed with the SAE and AMPE, and later the same mesh STA is detected again. The sta_state of the mesh STA remains at IEEE80211_STA_NONE and if the ieee80211_sta_ps_deliver_wakeup is called and subsequently the ath_tx_aggr_wakeup, the kernel panic due to ath_tx_node_init is not called before to initialize the require data structures. This issue is reported by Cedric Voncken before. http://www.spinics.net/lists/linux-wireless/msg106342.html [<831ea6b4>] ath_tx_aggr_wakeup+0x44/0xcc [ath9k] [<83084214>] ieee80211_sta_ps_deliver_wakeup+0xb8/0x208 [mac80211] [<830b9824>] ieee80211_mps_sta_status_update+0x94/0x108 [mac80211] [<83099398>] ieee80211_sta_ps_transition+0xc94/0x34d8 [mac80211] [<8022399c>] nf_iterate+0x98/0x104 [<8309bb60>] ieee80211_sta_ps_transition+0x345c/0x34d8 [mac80211] Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 3b7bfc0..22290a9 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta) enum nl80211_mesh_power_mode pm; bool do_buffer; + /* For non-assoc STA, prevent buffering or frame transmission */ + if (sta->sta_state < IEEE80211_STA_ASSOC) + return; + /* * use peer-specific power mode if peering is established and the * peer's power mode is known -- cgit v0.10.2 From a1923f1d4723e5757cefdd60f7c7ab30e472007a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 18 Jul 2013 19:11:26 +0300 Subject: iwlwifi: add DELL SKU for 5150 HMC This SKU was missing in the list of supported devices https://bugzilla.kernel.org/show_bug.cgi?id=60577 Cc: [all versions] Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 81f3ea5..ff13458 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */ + {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */ {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */ {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */ -- cgit v0.10.2 From c63e0e370028d7e4033bd40165f18499872b5183 Mon Sep 17 00:00:00 2001 From: Nestor Lopez Casado Date: Thu, 18 Jul 2013 06:21:30 -0700 Subject: HID: Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue"" This reverts commit 8af6c08830b1ae114d1a8b548b1f8b056e068887. This patch re-adds the workaround introduced by 596264082f10dd4 which was reverted by 8af6c08830b1ae114. The original patch 596264 was needed to overcome a situation where the hid-core would drop incoming reports while probe() was being executed. This issue was solved by c849a6143bec520af which added hid_device_io_start() and hid_device_io_stop() that enable a specific hid driver to opt-in for input reports while its probe() is being executed. Commit a9dd22b730857347 modified hid-logitech-dj so as to use the functionality added to hid-core. Having done that, workaround 596264 was no longer necessary and was reverted by 8af6c08. We now encounter a different problem that ends up 'again' thwarting the Unifying receiver enumeration. The problem is time and usb controller dependent. Ocasionally the reports sent to the usb receiver to start the paired devices enumeration fail with -EPIPE and the receiver never gets to enumerate the paired devices. With dcd9006b1b053c7b1c the problem was "hidden" as the call to the usb driver became asynchronous and none was catching the error from the failing URB. As the root cause for this failing SET_REPORT is not understood yet, -possibly a race on the usb controller drivers or a problem with the Unifying receiver- reintroducing this workaround solves the problem. Overall what this workaround does is: If an input report from an unknown device is received, then a (re)enumeration is performed. related bug: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1194649 Signed-off-by: Nestor Lopez Casado Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 5207591a..cd33084 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver; static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, size_t count, unsigned char report_type); +static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report) @@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & SPFUNCTION_DEVICE_LIST_EMPTY) { dbg_hid("%s: device list is empty\n", __func__); + djrcv_dev->querying_devices = false; return; } @@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, return; } + if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { + /* The device is already known. No need to reallocate it. */ + dbg_hid("%s: device is already known\n", __func__); + return; + } + dj_hiddev = hid_allocate_device(); if (IS_ERR(dj_hiddev)) { dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", @@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work) struct dj_report dj_report; unsigned long flags; int count; + int retval; dbg_hid("%s\n", __func__); @@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work) logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); break; default: + /* A normal report (i. e. not belonging to a pair/unpair notification) + * arriving here, means that the report arrived but we did not have a + * paired dj_device associated to the report's device_index, this + * means that the original "device paired" notification corresponding + * to this dj_device never arrived to this driver. The reason is that + * hid-core discards all packets coming from a device while probe() is + * executing. */ + if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) { + /* ok, we don't know the device, just re-ask the + * receiver for the list of connected devices. */ + retval = logi_dj_recv_query_paired_devices(djrcv_dev); + if (!retval) { + /* everything went fine, so just leave */ + break; + } + dev_err(&djrcv_dev->hdev->dev, + "%s:logi_dj_recv_query_paired_devices " + "error:%d\n", __func__, retval); + } dbg_hid("%s: unexpected report type\n", __func__); } } @@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, if (!djdev) { dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" " is NULL, index %d\n", dj_report->device_index); + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); + + if (schedule_work(&djrcv_dev->work) == 0) { + dbg_hid("%s: did not schedule the work item, was already " + "queued\n", __func__); + } return; } @@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, if (dj_device == NULL) { dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" " is NULL, index %d\n", dj_report->device_index); + kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report)); + + if (schedule_work(&djrcv_dev->work) == 0) { + dbg_hid("%s: did not schedule the work item, was already " + "queued\n", __func__); + } return; } @@ -444,6 +484,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) struct dj_report *dj_report; int retval; + /* no need to protect djrcv_dev->querying_devices */ + if (djrcv_dev->querying_devices) + return 0; + dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) return -ENOMEM; @@ -455,6 +499,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) return retval; } + static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, unsigned timeout) { diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h index fd28a5e..4a40003 100644 --- a/drivers/hid/hid-logitech-dj.h +++ b/drivers/hid/hid-logitech-dj.h @@ -101,6 +101,7 @@ struct dj_receiver_dev { struct work_struct work; struct kfifo notif_fifo; spinlock_t lock; + bool querying_devices; }; struct dj_device { -- cgit v0.10.2 From 407a2c2a4d85100c8c67953e4bac2f4a6c942335 Mon Sep 17 00:00:00 2001 From: Nestor Lopez Casado Date: Thu, 18 Jul 2013 06:21:31 -0700 Subject: HID: hid-logitech-dj: querying_devices was never set Set querying_devices flag to true when we start the enumeration process. This was missing from the original patch. It never produced undesirable effects as it is highly improbable to have a second enumeration triggered while a first one was still in progress. Signed-off-by: Nestor Lopez Casado Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index cd33084..7a57648 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -488,6 +488,8 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) if (djrcv_dev->querying_devices) return 0; + djrcv_dev->querying_devices = true; + dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) return -ENOMEM; -- cgit v0.10.2 From ab8d46c0609843a83aef3f486365ca5e7c21d537 Mon Sep 17 00:00:00 2001 From: Tetsuyuki Kobayashi Date: Mon, 22 Jul 2013 14:58:17 +0100 Subject: ARM: 7788/1: elf: fix lpae hwcap feature reporting in proc/cpuinfo Commit a469abd0f868 ("ARM: elf: add new hwcap for identifying atomic ldrd/strd instructions") added a new hwcap to identify LPAE on CPUs which support it. Whilst the hwcap data is correct, the string reported in /proc/cpuinfo actually matches on HWCAP_VFPD32, which was missing an entry in the string table. This patch fixes this problem by adding a "vfpd32" string at the correct offset, preventing us from falsely advertising LPAE on CPUs which do not support it. [will: added commit message] Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Tetsuyuki Kobayashi Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 63af9a7..96286cb 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -971,6 +971,7 @@ static const char *hwcap_str[] = { "vfpv4", "idiva", "idivt", + "vfpd32", "lpae", NULL }; -- cgit v0.10.2 From 232fde062e0a2cc52e8e18a50cda361b4ba88f34 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sat, 13 Jul 2013 10:57:10 -0400 Subject: mwifiex: fix IRQ enable/disable During tear down (e.g. mwifiex_sdio_remove during system suspend), mwifiex left IRQs enabled for a significant period of time when it was unable to handle them correctly. This caused interrupt storms and interfered with the bluetooth interface on the same SDIO card. Solve this by disabling interrupts at the point when they can no longer be handled correctly, which is at the start of mwifiex_remove_card(). For cleanliness, we now enable interrupts in the mwifiex_add_card() path, to be symmetrical with the disabling of interrupts. We also couple the registration of the sdio IRQ handler with the actual enable/disable of interrupts at the hardware level. I also removed a write to this register in mwifiex_init_sdio which seemed pointless and won't cause any ill effects now that we only register the SDIO IRQ handler when we are ready to accept interrupts. Includes some corrections from Amitkumar Karwar. Signed-off-by: Daniel Drake Acked-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index caaf4bd..2cf8b96 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -693,7 +693,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, if (!ret) { dev_notice(adapter->dev, "WLAN FW already running! Skip FW dnld\n"); - goto done; + return 0; } poll_num = MAX_FIRMWARE_POLL_TRIES; @@ -719,14 +719,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_fw: /* Check if the firmware is downloaded successfully or not */ ret = adapter->if_ops.check_fw_status(adapter, poll_num); - if (ret) { + if (ret) dev_err(adapter->dev, "FW failed to be active in time\n"); - return -1; - } -done: - /* re-enable host interrupt for mwifiex after fw dnld is successful */ - if (adapter->if_ops.enable_int) - adapter->if_ops.enable_int(adapter); return ret; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index e15ab72..1753431 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -427,6 +427,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) "Cal data request_firmware() failed\n"); } + /* enable host interrupt after fw dnld is successful */ + if (adapter->if_ops.enable_int) + adapter->if_ops.enable_int(adapter); + adapter->init_wait_q_woken = false; ret = mwifiex_init_fw(adapter); if (ret == -1) { @@ -478,6 +482,8 @@ err_add_intf: mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); err_init_fw: + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); pr_debug("info: %s: unregister device\n", __func__); adapter->if_ops.unregister_dev(adapter); done: @@ -855,7 +861,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); /* Register the device. Fill up the private data structure with relevant - information from the card and request for the required IRQ. */ + information from the card. */ if (adapter->if_ops.register_dev(adapter)) { pr_err("%s: failed to register mwifiex device\n", __func__); goto err_registerdev; @@ -919,6 +925,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) if (!adapter) goto exit_remove; + /* We can no longer handle interrupts once we start doing the teardown + * below. */ + if (adapter->if_ops.disable_int) + adapter->if_ops.disable_int(adapter); + adapter->surprise_removed = true; /* Stop data */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 3da73d3..253e0bd 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -601,6 +601,7 @@ struct mwifiex_if_ops { int (*register_dev) (struct mwifiex_adapter *); void (*unregister_dev) (struct mwifiex_adapter *); int (*enable_int) (struct mwifiex_adapter *); + void (*disable_int) (struct mwifiex_adapter *); int (*process_int_status) (struct mwifiex_adapter *); int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *, struct mwifiex_tx_param *); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5ee5ed0..5ef49f2 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -51,6 +51,7 @@ static struct mwifiex_if_ops sdio_ops; static struct semaphore add_remove_card_sem; static int mwifiex_sdio_resume(struct device *dev); +static void mwifiex_sdio_interrupt(struct sdio_func *func); /* * SDIO probe. @@ -296,6 +297,15 @@ static struct sdio_driver mwifiex_sdio = { } }; +/* Write data into SDIO card register. Caller claims SDIO device. */ +static int +mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data) +{ + int ret = -1; + sdio_writeb(func, data, reg, &ret); + return ret; +} + /* * This function writes data into SDIO card register. */ @@ -303,10 +313,10 @@ static int mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data) { struct sdio_mmc_card *card = adapter->card; - int ret = -1; + int ret; sdio_claim_host(card->func); - sdio_writeb(card->func, data, reg, &ret); + ret = mwifiex_write_reg_locked(card->func, reg, data); sdio_release_host(card->func); return ret; @@ -685,23 +695,15 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) * The host interrupt mask is read, the disable bit is reset and * written back to the card host interrupt mask register. */ -static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) +static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) { - u8 host_int_mask, host_int_disable = HOST_INT_DISABLE; - - /* Read back the host_int_mask register */ - if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) - return -1; - - /* Update with the mask and write back to the register */ - host_int_mask &= ~host_int_disable; - - if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { - dev_err(adapter->dev, "disable host interrupt failed\n"); - return -1; - } + struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; - return 0; + sdio_claim_host(func); + mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0); + sdio_release_irq(func); + sdio_release_host(func); } /* @@ -713,14 +715,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; + struct sdio_func *func = card->func; + int ret; + + sdio_claim_host(func); + + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); + if (ret) { + dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret); + goto out; + } /* Simply write the mask to the register */ - if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, - card->reg->host_int_enable)) { + ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, + card->reg->host_int_enable); + if (ret) { dev_err(adapter->dev, "enable host interrupt failed\n"); - return -1; + sdio_release_irq(func); } - return 0; + +out: + sdio_release_host(func); + return ret; } /* @@ -997,9 +1014,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func) } adapter = card->adapter; - if (adapter->surprise_removed) - return; - if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; @@ -1728,9 +1742,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter) struct sdio_mmc_card *card = adapter->card; if (adapter->card) { - /* Release the SDIO IRQ */ sdio_claim_host(card->func); - sdio_release_irq(card->func); sdio_disable_func(card->func); sdio_release_host(card->func); sdio_set_drvdata(card->func, NULL); @@ -1744,7 +1756,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter) */ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) { - int ret = 0; + int ret; struct sdio_mmc_card *card = adapter->card; struct sdio_func *func = card->func; @@ -1753,22 +1765,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) sdio_claim_host(func); - /* Request the SDIO IRQ */ - ret = sdio_claim_irq(func, mwifiex_sdio_interrupt); - if (ret) { - pr_err("claim irq failed: ret=%d\n", ret); - goto disable_func; - } - /* Set block size */ ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE); + sdio_release_host(func); if (ret) { pr_err("cannot set SDIO block size\n"); - ret = -1; - goto release_irq; + return ret; } - sdio_release_host(func); sdio_set_drvdata(func, card); adapter->dev = &func->dev; @@ -1776,15 +1780,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) strcpy(adapter->fw_name, card->firmware); return 0; - -release_irq: - sdio_release_irq(func); -disable_func: - sdio_disable_func(func); - sdio_release_host(func); - adapter->card = NULL; - - return -1; } /* @@ -1813,9 +1808,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) */ mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg); - /* Disable host interrupt mask register for SDIO */ - mwifiex_sdio_disable_host_int(adapter); - /* Get SDIO ioport */ mwifiex_init_sdio_ioport(adapter); @@ -1957,6 +1949,7 @@ static struct mwifiex_if_ops sdio_ops = { .register_dev = mwifiex_register_dev, .unregister_dev = mwifiex_unregister_dev, .enable_int = mwifiex_sdio_enable_host_int, + .disable_int = mwifiex_sdio_disable_host_int, .process_int_status = mwifiex_process_int_status, .host_to_card = mwifiex_sdio_host_to_card, .wakeup = mwifiex_pm_wakeup_card, diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6d51dfd..532ae0a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -92,9 +92,6 @@ /* Host Control Registers : Download host interrupt mask */ #define DN_LD_HOST_INT_MASK (0x2U) -/* Disable Host interrupt mask */ -#define HOST_INT_DISABLE 0xff - /* Host Control Registers : Host interrupt status */ #define HOST_INTSTATUS_REG 0x03 /* Host Control Registers : Upload host interrupt status */ -- cgit v0.10.2 From dc2a87f519a4d8cb376ab54f22b6b98a943b51ce Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 19 Jul 2013 20:16:17 +0200 Subject: ath9k_htc: do some initial hardware configuration Currently we configure harwdare and clock, only after interface start. In this case, if we reload module or reboot PC without configuring adapter, firmware will freeze. There is no software way to reset adpter. This patch add initial configuration and set it in disabled state, to avoid this freeze. Behaviour of this patch should be similar to: ifconfig wlan0 up; ifconfig wlan0 down. Bug: https://github.com/qca/open-ath9k-htc-firmware/issues/1 Tested-by: Bo Shi Signed-off-by: Oleksij Rempel Cc: Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 71a183f..c3676bf 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; + ath9k_hw_disable(priv->ah); #ifdef CONFIG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, -- cgit v0.10.2 From 4928bd2ef8ece262f4f314630219999a91eaa440 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 19 Jul 2013 20:16:18 +0200 Subject: ath9k_htc: reboot firmware if it was loaded Currently ath9k_htc will reboot firmware only if interface was ever started. Which lead to the problem in case where interface was never started but module need to be reloaded. This patch will partially fix bug "ath9k_htc: Target is unresponsive" https://github.com/qca/open-ath9k-htc-firmware/issues/1 Reproduction case: - plug adapter - make sure nothing will touch it. Stop Networkmanager or blacklist mac address of this adapter. - rmmod ath9k_htc; sleep 1; modprobe ath9k_htc Signed-off-by: Oleksij Rempel Cc: Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 2469db5..5205a36 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); - if (!unplugged && (hif_dev->flags & HIF_USB_START)) + /* If firmware was loaded we should drop it + * go back to first stage bootloader. */ + if (!unplugged && (hif_dev->flags & HIF_USB_READY)) ath9k_hif_usb_reboot(udev); kfree(hif_dev); -- cgit v0.10.2 From 16ec75b5de6479637993ad0f7c11a49aae069f68 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Fri, 19 Jul 2013 23:31:27 -0400 Subject: cw1200: Fix OOPS in monitor mode In monitor mode, priv->vif is NULL, but at one point in the receive path we blindly attempt to dereference it. Add a test to prevent this. Signed-off-by: Solomon Peachy Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/cw1200/txrx.c b/drivers/net/wireless/cw1200/txrx.c index 5862c37..e824d4d 100644 --- a/drivers/net/wireless/cw1200/txrx.c +++ b/drivers/net/wireless/cw1200/txrx.c @@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv, if (cw1200_handle_action_rx(priv, skb)) return; } else if (ieee80211_is_beacon(frame->frame_control) && - !arg->status && + !arg->status && priv->vif && !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid, ETH_ALEN)) { const u8 *tim_ie; -- cgit v0.10.2 From 5d21608a592a9afcac8d82c6478a564e911ce70b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 20 Jul 2013 21:46:48 -0500 Subject: ath: wil6210: Fix build error Building driver wil6210 in 3.10 and 3.11 kernels yields the following errors: CC [M] drivers/net/wireless/ath/wil6210/debugfs.o drivers/net/wireless/ath/wil6210/debugfs.c: In function 'wil_print_ring': drivers/net/wireless/ath/wil6210/debugfs.c:163:11: error: pointer targets in passing argument 5 of 'hex_dump_to_buffer' differ in signedness [-Werror=pointer-sign] false); ^ In file included from include/linux/kernel.h:13:0, from include/linux/cache.h:4, from include/linux/time.h:4, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/net/wireless/ath/wil6210/debugfs.c:17: include/linux/printk.h:361:13: note: expected 'char *' but argument is of type 'unsigned char *' extern void hex_dump_to_buffer(const void *buf, size_t len, ^ drivers/net/wireless/ath/wil6210/debugfs.c: In function 'wil_txdesc_debugfs_show': drivers/net/wireless/ath/wil6210/debugfs.c:429:10: error: pointer targets in passing argument 5 of 'hex_dump_to_buffer' differ in signedness [-Werror=pointer-sign] sizeof(printbuf), false); ^ In file included from include/linux/kernel.h:13:0, from include/linux/cache.h:4, from include/linux/time.h:4, from include/linux/stat.h:18, from include/linux/module.h:10, from drivers/net/wireless/ath/wil6210/debugfs.c:17: include/linux/printk.h:361:13: note: expected 'char *' but argument is of type 'unsigned char *' extern void hex_dump_to_buffer(const void *buf, size_t len, ^ cc1: all warnings being treated as errors make[5]: *** [drivers/net/wireless/ath/wil6210/debugfs.o] Error 1 make[4]: *** [drivers/net/wireless/ath/wil6210] Error 2 make[3]: *** [drivers/net/wireless/ath] Error 2 make[2]: *** [drivers/net/wireless] Error 2 make[1]: *** [drivers/net] Error 2 make: *** [drivers] Error 2 These errors are fixed by changing the type of the buffer from "unsigned char *" to "char *". Reported-by: Thomas Fjellstrom Tested-by: Thomas Fjellstrom Signed-off-by: Larry Finger Cc: Stable [3.10] Cc: Thomas Fjellstrom Signed-off-by: Vladimir Kondratiev Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index e8308ec..ab63676 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, le16_to_cpu(hdr.type), hdr.flags); if (len <= MAX_MBOXITEM_SIZE) { int n = 0; - unsigned char printbuf[16 * 3 + 2]; + char printbuf[16 * 3 + 2]; unsigned char databuf[MAX_MBOXITEM_SIZE]; void __iomem *src = wmi_buffer(wil, d.addr) + sizeof(struct wil6210_mbox_hdr); @@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) seq_printf(s, " SKB = %p\n", skb); if (skb) { - unsigned char printbuf[16 * 3 + 2]; + char printbuf[16 * 3 + 2]; int i = 0; int len = le16_to_cpu(d->dma.length); void *p = skb->data; -- cgit v0.10.2 From 28a905b51c2b3fabbb0eb53af229fc365200e398 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Mon, 22 Jul 2013 20:31:22 +0200 Subject: brcmfmac: decrement pending 8021x count upon tx failure If the transmit fails because there are no hanger slots or any other reason and the packet was an EAPOL packet the pending counter should be decreased although it was not transmitted so the driver does not end up in a dead-lock. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index f0d9f7f..29b1f24 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) ulong flags; int fifo = BRCMF_FWS_FIFO_BCMC; bool multicast = is_multicast_ether_addr(eh->h_dest); + bool pae = eh->h_proto == htons(ETH_P_PAE); /* determine the priority */ if (!skb->priority) skb->priority = cfg80211_classify8021d(skb); drvr->tx_multicast += !!multicast; - if (ntohs(eh->h_proto) == ETH_P_PAE) + if (pae) atomic_inc(&ifp->pend_8021x_cnt); if (!brcmf_fws_fc_active(fws)) { @@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_fws_schedule_deq(fws); } else { brcmf_err("drop skb: no hanger slot\n"); + if (pae) { + atomic_dec(&ifp->pend_8021x_cnt); + if (waitqueue_active(&ifp->pend_8021x_wait)) + wake_up(&ifp->pend_8021x_wait); + } brcmu_pkt_buf_free_skb(skb); } brcmf_fws_unlock(drvr, flags); -- cgit v0.10.2 From 23d412a2e94f55b84dbf9d5e64f381677bc90575 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Mon, 22 Jul 2013 12:46:24 +0200 Subject: brcmfmac: bail out of brcmf_txflowblock_if() for non-netdev interface To avoid ending up in a NULL-pointer access, the function brcmf_txflowblock_if() should only be called for interfaces that have a netdev associated with it. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 8e89755..8009901 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, { unsigned long flags; - if (!ifp) + if (!ifp || !ifp->ndev) return; brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n", -- cgit v0.10.2 From f0e61604d747bf541808a1ebde6eeaef57e904e4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 19 Jul 2013 08:26:09 +0200 Subject: net: pch_gbe depends on x86 Since 4bb1667255a86360721291fe59991d033bbc2f2a (build some drivers only when compile-testing), PTP_1588_CLOCK_PCH depends on (X86 || COMPILE_TEST). But PCH_GBE selects PTP_1588_CLOCK_PCH without depending on x86. Fix this by adding the same dependency here. Signed-off-by: Jiri Slaby Reported-by: [intel's build test robot] Cc: "David S. Miller" Cc: Ben Hutchings Cc: netdev@vger.kernel.org Cc: Greg Kroah-Hartman Cc: kbuild-all@01.org Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig index cb22341..a588ffd 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig +++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig @@ -4,7 +4,7 @@ config PCH_GBE tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE" - depends on PCI + depends on PCI && (X86 || COMPILE_TEST) select MII select PTP_1588_CLOCK_PCH ---help--- -- cgit v0.10.2 From 7aa0076c497d6f0d5d957b431d0d80e1e9780274 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 23 Jul 2013 00:17:25 +0100 Subject: sfc: Enable RX scatter for flows steered by RFS Received packets are only scattered if this is enabled in both the matching filter and the receiving queue. This was not being done for filters inserted for RFS, so any packet requiring more than a single descriptor was dropped. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c index b74a60a..2a469b2 100644 --- a/drivers/net/ethernet/sfc/filter.c +++ b/drivers/net/ethernet/sfc/filter.c @@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4); ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); - efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index); + efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, + efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0, + rxq_index); rc = efx_filter_set_ipv4_full(&spec, ip->protocol, ip->daddr, ports[1], ip->saddr, ports[0]); if (rc) -- cgit v0.10.2 From cd34f647a78e7f2296fcb72392b9e5c832793e65 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 23 Jul 2013 13:56:50 +0200 Subject: mac80211: fix monitor interface suspend crash regression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My commit: commit 12e7f517029dad819c45eca9ca01fdb9ba57616b Author: Stanislaw Gruszka Date: Thu Feb 28 10:55:26 2013 +0100 mac80211: cleanup generic suspend/resume procedures removed check for deleting MONITOR and AP_VLAN when suspend. That can cause a crash (i.e. in iwlagn_mac_remove_interface()) since we remove interface in the driver that we did not add before. Reference: http://marc.info/?l=linux-kernel&m=137391815113860&w=2 Bisected-by: Ortwin Glück Reported-and-tested-by: Ortwin Glück Cc: stable@vger.kernel.org # 3.10 Signed-off-by: Stanislaw Gruszka Signed-off-by: Johannes Berg diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 7fc5d0d..3401262 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -99,10 +99,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) } mutex_unlock(&local->sta_mtx); - /* remove all interfaces */ + /* remove all interfaces that were created in the driver */ list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) + if (!ieee80211_sdata_running(sdata) || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sdata->vif.type == NL80211_IFTYPE_MONITOR) continue; + drv_remove_interface(local, sdata); } -- cgit v0.10.2 From 2451ade070ef9b0a0f118ac41896da856e72b5a1 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Sun, 21 Jul 2013 15:17:54 +0000 Subject: xen/arm,arm64: update xen_restart after ff701306cd49 and 7b6d864b48d9 Commit 7b6d864b48d9 (reboot: arm: change reboot_mode to use enum reboot_mode) and ff701306cd49 (arm64: use common reboot infrastructure) change the prototype of arm_pm_restart on arm and arm64. Update xen_restart accordingly. Signed-off-by: Stefano Stabellini diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index f71c37e..c9770ba 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -172,7 +172,7 @@ static void __init xen_percpu_init(void *unused) enable_percpu_irq(xen_events_irq, 0); } -static void xen_restart(char str, const char *cmd) +static void xen_restart(enum reboot_mode reboot_mode, const char *cmd) { struct sched_shutdown r = { .reason = SHUTDOWN_reboot }; int rc; -- cgit v0.10.2 From f8c0aca9fda7856a8a8d61d523ba3187affbd714 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jul 2013 16:20:36 -0300 Subject: fec: Add MODULE_ALIAS Add MODULE_ALIAS, so that auto module loading can work. Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d3ad5ea..f0f0e96 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2279,4 +2279,5 @@ static struct platform_driver fec_driver = { module_platform_driver(fec_driver); +MODULE_ALIAS("platform:"DRIVER_NAME); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 5312e54d7e8bfe9716a1ffbc50e0093aadde46b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 22 Jul 2013 18:26:56 +0200 Subject: iwlwifi: mvm: use only a single GTK in D3 Unfortunately, the firmware only supports replay counters for a single GTK in D3, so that we should only upload the last key and use its replay counters. Since mac80211 key iteration will walk through the keys in order of their addition, simply use the same HW key index (1) for all GTKs, thus overwriting previous ones with newer ones. The replay counters for it are already used. Reviewed-by: Yaron Vaknin Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 7e5e5c2..83da884 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -134,7 +134,7 @@ struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_tkip_params_cmd *tkip; bool error, use_rsc_tsc, use_tkip; - int gtk_key_idx; + int wep_key_idx; }; static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, @@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, wkc.wep_key.key_offset = 0; } else { /* others start at 1 */ - data->gtk_key_idx++; - wkc.wep_key.key_offset = data->gtk_key_idx; + data->wep_key_idx++; + wkc.wep_key.key_offset = data->wep_key_idx; } ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC, @@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, mvm->ptk_ivlen = key->iv_len; mvm->ptk_icvlen = key->icv_len; } else { - data->gtk_key_idx++; - key->hw_key_idx = data->gtk_key_idx; + /* + * firmware only supports TSC/RSC for a single key, + * so if there are multiple keep overwriting them + * with new ones -- this relies on mac80211 doing + * list_add_tail(). + */ + key->hw_key_idx = 1; mvm->gtk_ivlen = key->iv_len; mvm->gtk_icvlen = key->icv_len; } -- cgit v0.10.2 From bb963c4a43eb5127eb0bbfa16c7a6a209b0af5db Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Tue, 23 Jul 2013 14:13:32 +0300 Subject: iwlwifi: mvm: set SSID bits for passive channels Set SSID bitmap for direct scan even on passive channels, for the passive-to-active feature. Without this patch only the SSID from probe request template is sent on passive channels, after passive-to-active switching, causing us to not find all desired networks. Remove the unused passive scan mask constant. Cc: stable@vger.kernel.org Reviewed-by: Emmanuel Grumbach Signed-off-by: David Spinadel Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index b60d141..365095a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -69,7 +69,6 @@ /* Scan Commands, Responses, Notifications */ /* Masks for iwl_scan_channel.type flags */ -#define SCAN_CHANNEL_TYPE_PASSIVE 0 #define SCAN_CHANNEL_TYPE_ACTIVE BIT(0) #define SCAN_CHANNEL_NARROW_BAND BIT(22) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 268f027..acdff6b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -178,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, struct iwl_scan_channel *chan = (struct iwl_scan_channel *) (cmd->data + le16_to_cpu(cmd->tx_cmd.len)); int i; - __le32 chan_type_value; - - if (req->n_ssids > 0) - chan_type_value = cpu_to_le32(BIT(req->n_ssids) - 1); - else - chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE; for (i = 0; i < cmd->channel_count; i++) { chan->channel = cpu_to_le16(req->channels[i]->hw_value); + chan->type = cpu_to_le32(BIT(req->n_ssids) - 1); if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) - chan->type = SCAN_CHANNEL_TYPE_PASSIVE; - else - chan->type = chan_type_value; + chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); chan->active_dwell = cpu_to_le16(active_dwell); chan->passive_dwell = cpu_to_le16(passive_dwell); chan->iteration_count = cpu_to_le16(1); -- cgit v0.10.2 From 56a678344273fd63f8ade26876283a2586a9bf3a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jul 2013 15:27:35 +0200 Subject: ASoC: dapm: Fix return value of snd_soc_dapm_put_{volsw,enum_virt}() The ALSA core expect the put callback of a control to return 1 if the value of the control changed and 0 if it did not. Both snd_soc_dapm_put_volsw() and snd_soc_dapm_put_enum_virt() currently always returns 0. For both functions we already have a 'change' variable which either contains 1 or 0 depending on whether the value has changed or not, so just return that. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b941908..bd16010 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2733,7 +2733,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, } mutex_unlock(&card->dapm_mutex); - return 0; + return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); @@ -2861,7 +2861,6 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int change; - int ret = 0; int wi; if (ucontrol->value.enumerated.item[0] >= e->max) @@ -2881,7 +2880,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, } mutex_unlock(&card->dapm_mutex); - return ret; + return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); -- cgit v0.10.2 From 6f498018279d118cf38945f73da7c9345f7e2e5d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 24 Jul 2013 16:53:07 +0200 Subject: HID: sony: fix HID mapping for PS3 sixaxis controller Commit f04d51404f51 (HID: driver for PS2/3 Buzz controllers) introduced an input_mapping() callback, but set the return value to -1 to all devices except the Buzz controllers. The result of this is that the Sixaxis input device is not populated, making it useless. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ecbc749..87fbe29 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -369,7 +369,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, if (sc->quirks & PS3REMOTE) return ps3remote_mapping(hdev, hi, field, usage, bit, max); - return -1; + /* Let hid-core decide for the others */ + return 0; } /* -- cgit v0.10.2 From de9c7602ca25f52bbfeb52e7d85765fe70b92dce Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 10 Jun 2013 16:40:56 -0600 Subject: vfio: Don't overreact to DEL_DEVICE BUS_NOTIFY_DEL_DEVICE triggers IOMMU drivers to remove devices from their iommu group, but there's really nothing we can do about it at this point. If the device is in use, then the vfio sub-driver will block the device_del from completing until it's released. If the device is not in use or not owned by a vfio sub-driver, then we really don't care that it's being removed. The current code can be triggered just by unloading an sr-iov driver (ex. igb) while the VFs are attached to vfio-pci because it makes an incorrect assumption about the ordering of driver remove callbacks vs the DEL_DEVICE notification. Signed-off-by: Alex Williamson diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index c488da5..6d18c3c 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -494,27 +494,6 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev) return 0; } -static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev) -{ - struct vfio_device *device; - - /* - * Expect to fall out here. If a device was in use, it would - * have been bound to a vfio sub-driver, which would have blocked - * in .remove at vfio_del_group_dev. Sanity check that we no - * longer track the device, so it's safe to remove. - */ - device = vfio_group_get_device(group, dev); - if (likely(!device)) - return 0; - - WARN("Device %s removed from live group %d!\n", dev_name(dev), - iommu_group_id(group->iommu_group)); - - vfio_device_put(device); - return 0; -} - static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev) { /* We don't care what happens when the group isn't in use */ @@ -545,7 +524,13 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, vfio_group_nb_add_dev(group, dev); break; case IOMMU_GROUP_NOTIFY_DEL_DEVICE: - vfio_group_nb_del_dev(group, dev); + /* + * Nothing to do here. If the device is in use, then the + * vfio sub-driver should block the remove callback until + * it is unused. If the device is unused or attached to a + * stub driver, then it should be released and we don't + * care that it will be going away. + */ break; case IOMMU_GROUP_NOTIFY_BIND_DRIVER: pr_debug("%s: Device %s, group %d binding to driver\n", -- cgit v0.10.2 From c64019302bbb0b445484d870e674ab34a19a18a1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 10 Jun 2013 16:40:56 -0600 Subject: vfio: Ignore sprurious notifies Remove debugging WARN_ON if we get a spurious notify for a group that no longer exists. No reports of anyone hitting this, but it would likely be a race and not a bug if they did. Signed-off-by: Alex Williamson diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 6d18c3c..842f450 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -510,13 +510,11 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, struct device *dev = data; /* - * Need to go through a group_lock lookup to get a reference or - * we risk racing a group being removed. Leave a WARN_ON for - * debuging, but if the group no longer exists, a spurious notify - * is harmless. + * Need to go through a group_lock lookup to get a reference or we + * risk racing a group being removed. Ignore spurious notifies. */ group = vfio_group_try_get(group); - if (WARN_ON(!group)) + if (!group) return NOTIFY_OK; switch (action) { -- cgit v0.10.2 From d24cdbfd28b7e0ffecb1e281d73e73c03a57f734 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 10 Jun 2013 16:40:57 -0600 Subject: vfio-pci: Avoid deadlock on remove If an attempt is made to unbind a device from vfio-pci while that device is in use, the request is blocked until the device becomes unused. Unfortunately, that unbind path still grabs the device_lock, which certain things like __pci_reset_function() also want to take. This means we need to try to acquire the locks ourselves and use the pre-locked version, __pci_reset_function_locked(). Signed-off-by: Alex Williamson diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index c5179e2..cef6002 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) */ pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); - if (vdev->reset_works) - __pci_reset_function(pdev); + /* + * Careful, device_lock may already be held. This is the case if + * a driver unbind is blocked. Try to get the locks ourselves to + * prevent a deadlock. + */ + if (vdev->reset_works) { + bool reset_done = false; + + if (pci_cfg_access_trylock(pdev)) { + if (device_trylock(&pdev->dev)) { + __pci_reset_function_locked(pdev); + reset_done = true; + device_unlock(&pdev->dev); + } + pci_cfg_access_unlock(pdev); + } + + if (!reset_done) + pr_warn("%s: Unable to acquire locks for reset of %s\n", + __func__, dev_name(&pdev->dev)); + } pci_restore_state(pdev); } -- cgit v0.10.2 From 4ea72445bddd2ca09fc719065fc3c5a8bfc8ca10 Mon Sep 17 00:00:00 2001 From: Lekensteyn Date: Mon, 22 Jul 2013 09:53:30 +0200 Subject: r8169: fix lockdep warning when removing interface The work queue is initialised in rtl_open (when the interface goes up), but canceled in rtl_remove_one (when the PCI device gets removed). If the network interface is not brought up, then the work queue struct is not initialised. When the device is removed, the attempt to cancel the uninitialised work queue causes a lockdep warning. This patch fixes the issue by moving cancel_work_sync to rtl_close (to match rtl_open). (Note that rtl_close is also called via unregister_netdev in rtl_remove_one.) Signed-off-by: Peter Wu Acked-by: Francois Romieu Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 4106a74..880015c 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(dev); rtl_unlock_work(tp); + cancel_work_sync(&tp->wk.work); + free_irq(pdev->irq, dev); dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, @@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev) rtl8168_driver_stop(tp); } - cancel_work_sync(&tp->wk.work); - netif_napi_del(&tp->napi); unregister_netdev(dev); -- cgit v0.10.2 From 64d2c22a4cdd3ce752ca700964a6120049d78aed Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jul 2013 11:02:01 +0300 Subject: mlx5: use after free in mlx5_cmd_comp_handler() We can't dereference "ent" after passing it to free_cmd(). Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 205753a..4037406 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1113,7 +1113,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) for (i = 0; i < (1 << cmd->log_sz); i++) { if (test_bit(i, &vector)) { + struct semaphore *sem; + ent = cmd->ent_arr[i]; + if (ent->page_queue) + sem = &cmd->pages_sem; + else + sem = &cmd->sem; ktime_get_ts(&ent->ts2); memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); dump_command(dev, ent, 0); @@ -1136,10 +1142,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) } else { complete(&ent->done); } - if (ent->page_queue) - up(&cmd->pages_sem); - else - up(&cmd->sem); + up(sem); } } } -- cgit v0.10.2 From f585a991e1d1612265f0d4e812f77e40dd54975b Mon Sep 17 00:00:00 2001 From: Jerry Snitselaar Date: Mon, 22 Jul 2013 12:01:58 -0700 Subject: fib_trie: potential out of bounds access in trie_show_stats() With the <= max condition in the for loop, it will be always go 1 element further than needed. If the condition for the while loop is never met, then max is MAX_STAT_DEPTH, and for loop will walk off the end of nodesizes[]. Signed-off-by: Jerry Snitselaar Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 49616fe..108a1e9c 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2133,7 +2133,7 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) max--; pointers = 0; - for (i = 1; i <= max; i++) + for (i = 1; i < max; i++) if (stat->nodesizes[i] != 0) { seq_printf(seq, " %u: %u", i, stat->nodesizes[i]); pointers += (1<nodesizes[i]; -- cgit v0.10.2 From 905a6f96a1b18e490a75f810d733ced93c39b0e5 Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Mon, 22 Jul 2013 23:45:53 +0200 Subject: ipv6: take rtnl_lock and mark mrt6 table as freed on namespace cleanup Otherwise we end up dereferencing the already freed net->ipv6.mrt pointer which leads to a panic (from Srivatsa S. Bhat): BUG: unable to handle kernel paging request at ffff882018552020 IP: [] ip6mr_sk_done+0x32/0xb0 [ipv6] PGD 290a067 PUD 207ffe0067 PMD 207ff1d067 PTE 8000002018552060 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC Modules linked in: ebtable_nat ebtables nfs fscache nf_conntrack_ipv4 nf_defrag_ipv4 ipt_REJECT xt_CHECKSUM iptable_mangle iptable_filter ip_tables nfsd lockd nfs_acl exportfs auth_rpcgss autofs4 sunrpc 8021q garp bridge stp llc ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 xt_state nf_conntrack ip6table_filter +ip6_tables ipv6 vfat fat vhost_net macvtap macvlan vhost tun kvm_intel kvm uinput iTCO_wdt iTCO_vendor_support cdc_ether usbnet mii microcode i2c_i801 i2c_core lpc_ich mfd_core shpchp ioatdma dca mlx4_core be2net wmi acpi_cpufreq mperf ext4 jbd2 mbcache dm_mirror dm_region_hash dm_log dm_mod CPU: 0 PID: 7 Comm: kworker/u33:0 Not tainted 3.11.0-rc1-ea45e-a #4 Hardware name: IBM -[8737R2A]-/00Y2738, BIOS -[B2E120RUS-1.20]- 11/30/2012 Workqueue: netns cleanup_net task: ffff8810393641c0 ti: ffff881039366000 task.ti: ffff881039366000 RIP: 0010:[] [] ip6mr_sk_done+0x32/0xb0 [ipv6] RSP: 0018:ffff881039367bd8 EFLAGS: 00010286 RAX: ffff881039367fd8 RBX: ffff882018552000 RCX: dead000000200200 RDX: 0000000000000000 RSI: ffff881039367b68 RDI: ffff881039367b68 RBP: ffff881039367bf8 R08: ffff881039367b68 R09: 2222222222222222 R10: 2222222222222222 R11: 2222222222222222 R12: ffff882015a7a040 R13: ffff882014eb89c0 R14: ffff8820289e2800 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88103fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff882018552020 CR3: 0000000001c0b000 CR4: 00000000000407f0 Stack: ffff881039367c18 ffff882014eb89c0 ffff882015e28c00 0000000000000000 ffff881039367c18 ffffffffa034d9d1 ffff8820289e2800 ffff882014eb89c0 ffff881039367c58 ffffffff815bdecb ffffffff815bddf2 ffff882014eb89c0 Call Trace: [] rawv6_close+0x21/0x40 [ipv6] [] inet_release+0xfb/0x220 [] ? inet_release+0x22/0x220 [] inet6_release+0x3f/0x50 [ipv6] [] sock_release+0x29/0xa0 [] sk_release_kernel+0x30/0x70 [] icmpv6_sk_exit+0x3b/0x80 [ipv6] [] ops_exit_list+0x39/0x60 [] cleanup_net+0xfb/0x1a0 [] process_one_work+0x1da/0x610 [] ? process_one_work+0x169/0x610 [] worker_thread+0x120/0x3a0 [] ? process_one_work+0x610/0x610 [] kthread+0xee/0x100 [] ? __init_kthread_worker+0x70/0x70 [] ret_from_fork+0x7c/0xb0 [] ? __init_kthread_worker+0x70/0x70 Code: 20 48 89 5d e8 4c 89 65 f0 4c 89 6d f8 66 66 66 66 90 4c 8b 67 30 49 89 fd e8 db 3c 1e e1 49 8b 9c 24 90 08 00 00 48 85 db 74 06 <4c> 39 6b 20 74 20 bb f3 ff ff ff e8 8e 3c 1e e1 89 d8 4c 8b 65 RIP [] ip6mr_sk_done+0x32/0xb0 [ipv6] RSP CR2: ffff882018552020 Reported-by: Srivatsa S. Bhat Tested-by: Srivatsa S. Bhat Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 583e8d4..03986d3 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -259,10 +259,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net) { struct mr6_table *mrt, *next; + rtnl_lock(); list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { list_del(&mrt->list); ip6mr_free_table(mrt); } + rtnl_unlock(); fib_rules_unregister(net->ipv6.mr6_rules_ops); } #else @@ -289,7 +291,10 @@ static int __net_init ip6mr_rules_init(struct net *net) static void __net_exit ip6mr_rules_exit(struct net *net) { + rtnl_lock(); ip6mr_free_table(net->ipv6.mrt6); + net->ipv6.mrt6 = NULL; + rtnl_unlock(); } #endif -- cgit v0.10.2 From 2bf420a7686e0fdd2fbf16d75e729b306744db0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Mon, 22 Jul 2013 22:09:18 -0300 Subject: net: sun4i: fix timeout check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current timeout check is comparing two constant values, so it won't ever detect a timeout. This patch reworks the affected code a bit so it has a chance at detecting timeouts correctly. Signed-off-by: Emilio López Acked-by: Maxime Ripard Signed-off-by: David S. Miller diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index 61d3f4e..7f25e49 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -40,7 +40,7 @@ struct sun4i_mdio_data { static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct sun4i_mdio_data *data = bus->priv; - unsigned long start_jiffies; + unsigned long timeout_jiffies; int value; /* issue the phy address and reg */ @@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum) writel(0x1, data->membase + EMAC_MAC_MCMD_REG); /* Wait read complete */ - start_jiffies = jiffies; + timeout_jiffies = jiffies + MDIO_TIMEOUT; while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_after(start_jiffies, - start_jiffies + MDIO_TIMEOUT)) + if (time_is_before_jiffies(timeout_jiffies)) return -ETIMEDOUT; msleep(1); } @@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct sun4i_mdio_data *data = bus->priv; - unsigned long start_jiffies; + unsigned long timeout_jiffies; /* issue the phy address and reg */ writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG); @@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum, writel(0x1, data->membase + EMAC_MAC_MCMD_REG); /* Wait read complete */ - start_jiffies = jiffies; + timeout_jiffies = jiffies + MDIO_TIMEOUT; while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) { - if (time_after(start_jiffies, - start_jiffies + MDIO_TIMEOUT)) + if (time_is_before_jiffies(timeout_jiffies)) return -ETIMEDOUT; msleep(1); } -- cgit v0.10.2 From deceb4c062a8dd63fe554c3be2b4bf9151a5cedf Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 23 Jul 2013 20:22:39 +0100 Subject: net: fix comment above build_skb() build_skb() specifies that the data parameter must come from a kmalloc'd area, this is only true if frag_size equals 0, because then build_skb() will use kzsize(data) to figure out the actual data size. Update the comment to reflect that special condition. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 20e02d2..3df4d4c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -309,7 +309,8 @@ EXPORT_SYMBOL(__alloc_skb); * @frag_size: size of fragment, or 0 if head was kmalloced * * Allocate a new &sk_buff. Caller provides space holding head and - * skb_shared_info. @data must have been allocated by kmalloc() + * skb_shared_info. @data must have been allocated by kmalloc() only if + * @frag_size is 0, otherwise data should come from the page allocator. * The return is the new skb buffer. * On a failure the return is %NULL, and @data is not freed. * Notes : -- cgit v0.10.2 From 23df0b731954502a9391e739b92927cee4360343 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 21 Jul 2013 16:36:48 +0300 Subject: regulatory: use correct regulatory initiator on wiphy register The current regdomain was not always set by the core. This causes cards with a custom regulatory domain to ignore user initiated changes if done before the card was registered. Signed-off-by: Arik Nemtsov Acked-by: Luis R. Rodriguez Signed-off-by: Johannes Berg diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5a950f3..de06d5d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) void wiphy_regulatory_register(struct wiphy *wiphy) { + struct regulatory_request *lr; + if (!reg_dev_ignore_cell_hint(wiphy)) reg_num_devs_support_basehint++; - wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); + lr = get_last_request(); + wiphy_update_regulatory(wiphy, lr->initiator); } void wiphy_regulatory_deregister(struct wiphy *wiphy) -- cgit v0.10.2 From 23a113a0f3b323738e5819365ab95e1eca7f0d58 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 24 Jul 2013 12:47:46 +0200 Subject: usb: gadget: ether: put_usb_function on unbind Fix bugs introduced in 9c62ce83e4258bacc459faf57bf2ed83cce6be08 usb: gadget: ether: convert to new interface of f_ecm 94b5573e97729f0e1496d23b69cbe2c6b24ec0c3 usb: gadget: ether: convert to new interface of f_eem 8af5232d6f48896b151898ccb2e9e155481bb785 usb: gadget: ether: convert to new interface of f_subset 9bd4a10e1bf881af0b0a7c117c7092b558447047 usb: gadget: ether: convert to new interface of f_rndis Acked-by: Michal Nazarewicz Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index f48712f..c1c113e 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -449,14 +449,20 @@ fail: static int __exit eth_unbind(struct usb_composite_dev *cdev) { - if (has_rndis()) + if (has_rndis()) { + usb_put_function(f_rndis); usb_put_function_instance(fi_rndis); - if (use_eem) + } + if (use_eem) { + usb_put_function(f_eem); usb_put_function_instance(fi_eem); - else if (can_support_ecm(cdev->gadget)) + } else if (can_support_ecm(cdev->gadget)) { + usb_put_function(f_ecm); usb_put_function_instance(fi_ecm); - else + } else { + usb_put_function(f_geth); usb_put_function_instance(fi_geth); + } return 0; } -- cgit v0.10.2 From 3b45b2a2ad3546591cb4407b1c66921b2ee158a8 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 25 Jul 2013 09:13:18 +0200 Subject: usb: gadget: free opts struct on error recovery Fix memory leaks introduced in commits: 40d133d7f542616cf9538508a372306e626a16e9 usb: gadget: f_ncm: convert to new function interface with backward compatibility fee562a6450b7806f1fbbe1469a67b5395b5c10a usb: gadget: f_ecm: convert to new function interface with backward compatibility fcbdf12ebef73a6069e2a1aada1e546fb578a4aa usb: gadget: f_phonet: convert to new function interface with backward compatibility b29002a157940752dfed2c488b2011f63f007d71 usb: gadget: f_eem: convert to new function interface with backward compatibility 8cedba7c73af1369599b1111639cfeb66fe13aaa usb: gadget: f_subset: convert to new function interface with backward compatibility f466c6353819326873fa48a02c6f2d7c903240d6 usb: gadget: f_rndis: convert to new function interface with backward compatibility Acked-by: Michal Nazarewicz Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 5d3561e..edab45d 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -959,8 +959,11 @@ static struct usb_function_instance *ecm_alloc_inst(void) mutex_init(&opts->lock); opts->func_inst.free_func_inst = ecm_free_inst; opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) - return ERR_PTR(PTR_ERR(opts->net)); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &ecm_func_type); diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 90ee802..d00392d 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -593,8 +593,11 @@ static struct usb_function_instance *eem_alloc_inst(void) mutex_init(&opts->lock); opts->func_inst.free_func_inst = eem_free_inst; opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) - return ERR_CAST(opts->net); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type); diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 952177f..1c28fe1 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1350,8 +1350,11 @@ static struct usb_function_instance *ncm_alloc_inst(void) mutex_init(&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) - return ERR_PTR(PTR_ERR(opts->net)); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 7944fb0..1bf26e9 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -656,8 +656,11 @@ static struct usb_function_instance *phonet_alloc_inst(void) opts->func_inst.free_func_inst = phonet_free_inst; opts->net = gphonet_setup_default(); - if (IS_ERR(opts->net)) - return ERR_PTR(PTR_ERR(opts->net)); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &phonet_func_type); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 191df35..717ed7f 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -963,8 +963,11 @@ static struct usb_function_instance *rndis_alloc_inst(void) mutex_init(&opts->lock); opts->func_inst.free_func_inst = rndis_free_inst; opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) - return ERR_CAST(opts->net); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &rndis_func_type); diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 5601e1d..7c8674f 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -505,8 +505,11 @@ static struct usb_function_instance *geth_alloc_inst(void) mutex_init(&opts->lock); opts->func_inst.free_func_inst = geth_free_inst; opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) - return ERR_CAST(opts->net); + if (IS_ERR(opts->net)) { + struct net_device *net = opts->net; + kfree(opts); + return ERR_CAST(net); + } config_group_init_type_name(&opts->func_inst.group, "", &gether_func_type); -- cgit v0.10.2 From da9910ac4a816b4340944c78d94c02a35527db46 Mon Sep 17 00:00:00 2001 From: Jaganath Kanakkassery Date: Fri, 21 Jun 2013 19:55:11 +0530 Subject: Bluetooth: Fix invalid length check in l2cap_information_rsp() The length check is invalid since the length varies with type of info response. This was introduced by the commit cb3b3152b2f5939d67005cff841a1ca748b19888 Because of this, l2cap info rsp is not handled and command reject is sent. > ACL data: handle 11 flags 0x02 dlen 16 L2CAP(s): Info rsp: type 2 result 0 Extended feature mask 0x00b8 Enhanced Retransmission mode Streaming mode FCS Option Fixed Channels < ACL data: handle 11 flags 0x00 dlen 10 L2CAP(s): Command rej: reason 0 Command not understood Cc: stable@vger.kernel.org Signed-off-by: Jaganath Kanakkassery Signed-off-by: Chan-Yeol Park Acked-by: Johan Hedberg Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4be6a26..68843a2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4333,7 +4333,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; u16 type, result; - if (cmd_len != sizeof(*rsp)) + if (cmd_len < sizeof(*rsp)) return -EPROTO; type = __le16_to_cpu(rsp->type); -- cgit v0.10.2 From 84eb2ae1807dd1467bf6f500fc69ae61f1907b75 Mon Sep 17 00:00:00 2001 From: Thomas Loo Date: Wed, 3 Jul 2013 02:53:54 +0200 Subject: Bluetooth: ath3k: Add support for Fujitsu Lifebook UH5x2 [04c5:1330] The Fujitsu Lifebook UH552/UH572 ships with a Qualcomm AR9462/AR3012 WLAN/BT-Combo card. Add device ID to the ath3k driver to enable the bluetooth side of things. Patch against v3.10. T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04c5 ProdID=1330 Rev=00.02 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: Thomas Loo Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 11f467c..b22376d 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -91,6 +91,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0489, 0xe04e) }, { USB_DEVICE(0x0489, 0xe056) }, { USB_DEVICE(0x0489, 0xe04d) }, + { USB_DEVICE(0x04c5, 0x1330) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -128,6 +129,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 7a7e5f8..8b8b85d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -151,6 +151,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From 517828a87994f41af6ae5a0f96f0f069f05baa81 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 8 Jul 2013 10:27:23 +0200 Subject: Bluetooth: ath3k: don't use stack memory for DMA Memory allocated by vmalloc (including stack) can not be used for DMA, i.e. data pointer on usb_control_msg() should not point to stack memory. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=977558 Reported-and-tested-by: Andy Lawrence Signed-off-by: Stanislaw Gruszka Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index b22376d..6f17e4d 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -195,24 +195,44 @@ error: static int ath3k_get_state(struct usb_device *udev, unsigned char *state) { - int pipe = 0; + int ret, pipe = 0; + char *buf; + + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; pipe = usb_rcvctrlpipe(udev, 0); - return usb_control_msg(udev, pipe, ATH3K_GETSTATE, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, - state, 0x01, USB_CTRL_SET_TIMEOUT); + ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT); + + *state = *buf; + kfree(buf); + + return ret; } static int ath3k_get_version(struct usb_device *udev, struct ath3k_version *version) { - int pipe = 0; + int ret, pipe = 0; + struct ath3k_version *buf; + const int size = sizeof(*buf); + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; pipe = usb_rcvctrlpipe(udev, 0); - return usb_control_msg(udev, pipe, ATH3K_GETVERSION, - USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version, - sizeof(struct ath3k_version), - USB_CTRL_SET_TIMEOUT); + ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + buf, size, USB_CTRL_SET_TIMEOUT); + + memcpy(version, buf, size); + kfree(buf); + + return ret; } static int ath3k_load_fwfile(struct usb_device *udev, -- cgit v0.10.2 From d9c78e9738ccd0017b10b8f44462aafb61904a4a Mon Sep 17 00:00:00 2001 From: Adam Lee Date: Wed, 10 Jul 2013 10:02:12 +0800 Subject: Bluetooth: fix wrong use of PTR_ERR() in btusb PTR_ERR() returns a signed long type value which is limited by IS_ERR(), it must be a negative number whose range is [-MAX_ERRNO, 0). The bug here returns negative numbers as error codes, then check it by "if (ret < 0)", but -PTR_ERR() is actually positive. The wrong use here leads to failure as below, even panic. [ 12.958920] Bluetooth: hci0 command 0xfc8e tx timeout [ 14.961765] Bluetooth: hci0 command 0xfc8e tx timeout [ 16.964688] Bluetooth: hci0 command 0xfc8e tx timeout [ 20.954501] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 22.957358] Bluetooth: hci0 command 0xfc8e tx timeout [ 30.948922] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 32.951780] Bluetooth: hci0 command 0xfc8e tx timeout [ 40.943359] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 42.946219] Bluetooth: hci0 command 0xfc8e tx timeout [ 50.937812] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 52.940670] Bluetooth: hci0 command 0xfc8e tx timeout [ 60.932236] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 62.935092] Bluetooth: hci0 command 0xfc8e tx timeout [ 70.926688] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 72.929545] Bluetooth: hci0 command 0xfc8e tx timeout [ 80.921111] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-110) [ 82.923969] Bluetooth: hci0 command 0xfc2f tx timeout [ 90.915542] Bluetooth: hci0 sending Intel patch command (0xfc2f) failed (-110) [ 92.918406] Bluetooth: hci0 command 0xfc11 tx timeout [ 100.909955] Bluetooth: hci0 sending Intel patch command (0xfc11) failed (-110) [ 102.912858] Bluetooth: hci0 command 0xfc60 tx timeout [ 110.904394] Bluetooth: hci0 sending Intel patch command (0xfc60) failed (-110) [ 112.907293] Bluetooth: hci0 command 0xfc11 tx timeout [ 120.898831] Bluetooth: hci0 exiting Intel manufacturer mode failed (-110) [ 120.904757] bluetoothd[1030]: segfault at 4 ip 00007f8b2eb55236 sp 00007fff53ff6920 error 4 in bluetoothd[7f8b2eaff000+cb000] Signed-off-by: Adam Lee Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8b8b85d..ad03394 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1093,7 +1093,7 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev, if (IS_ERR(skb)) { BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)", hdev->name, cmd->opcode, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } /* It ensures that the returned event matches the event data read from @@ -1145,7 +1145,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) if (IS_ERR(skb)) { BT_ERR("%s sending initial HCI reset command failed (%ld)", hdev->name, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } kfree_skb(skb); @@ -1159,7 +1159,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) if (IS_ERR(skb)) { BT_ERR("%s reading Intel fw version command failed (%ld)", hdev->name, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } if (skb->len != sizeof(*ver)) { @@ -1217,7 +1217,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_ERR("%s entering Intel manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); release_firmware(fw); - return -PTR_ERR(skb); + return PTR_ERR(skb); } if (skb->data[0]) { @@ -1274,7 +1274,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) if (IS_ERR(skb)) { BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } kfree_skb(skb); @@ -1290,7 +1290,7 @@ exit_mfg_disable: if (IS_ERR(skb)) { BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } kfree_skb(skb); @@ -1308,7 +1308,7 @@ exit_mfg_deactivate: if (IS_ERR(skb)) { BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); - return -PTR_ERR(skb); + return PTR_ERR(skb); } kfree_skb(skb); -- cgit v0.10.2 From 5b77a1f3d7b7360dc2b7c6d2188d39b9f8432907 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 15 Jul 2013 09:29:03 +0530 Subject: Bluetooth: ath3k: Add support for ID 0x13d3/0x3402 T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3402 Rev= 0.02 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Bug: https://bugzilla.kernel.org/show_bug.cgi?id=59701 Signed-off-by: Sujith Manoharan Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 6f17e4d..81973ec 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -92,6 +92,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0489, 0xe056) }, { USB_DEVICE(0x0489, 0xe04d) }, { USB_DEVICE(0x04c5, 0x1330) }, + { USB_DEVICE(0x13d3, 0x3402) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -130,6 +131,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ad03394..c4145c7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -152,6 +152,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From 1ebd0b21ab14efb75950079840eac29afea2a26e Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 17 Jul 2013 11:27:40 +0800 Subject: Bluetooth: Add support for Atheros [0cf3:3121] Add support for the AR3012 chip. T: Bus=03 Lev=01 Prnt=01 Port=06 Cnt=01 Dev#= 6 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3121 Rev=00.02 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: AceLan Kao Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 81973ec..d3a2d6f 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -93,6 +93,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0489, 0xe04d) }, { USB_DEVICE(0x04c5, 0x1330) }, { USB_DEVICE(0x13d3, 0x3402) }, + { USB_DEVICE(0x0cf3, 0x3121) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -132,6 +133,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c4145c7..fd5eaa3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -153,6 +153,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From fcee337704d76446e0d4714cc5eff53e896f7c6f Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 11 Jul 2013 11:34:28 +0100 Subject: Bluetooth: Fix race between hci_register_dev() and hci_dev_open() If hci_dev_open() is called after hci_register_dev() added the device to the hci_dev_list but before the workqueue are created we could run into a NULL pointer dereference (see below). This bug is very unlikely to happen, systems using bluetoothd to manage their bluetooth devices will never see this happen. BUG: unable to handle kernel NULL pointer dereference 0100 IP: [] __queue_work+0x32/0x3d0 (...) Call Trace: [] queue_work_on+0x45/0x50 [] hci_req_run+0xbf/0xf0 [bluetooth] [] ? hci_init2_req+0x720/0x720 [bluetooth] [] __hci_req_sync+0xd6/0x1c0 [bluetooth] [] ? try_to_wake_up+0x2b0/0x2b0 [] ? usb_autopm_put_interface+0x30/0x40 [] hci_dev_open+0x275/0x2e0 [bluetooth] [] hci_sock_ioctl+0x1f2/0x3f0 [bluetooth] [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x96/0x560 [] SyS_ioctl+0x91/0xb0 [] system_call_fastpath+0x1a/0x1f Reported-by: Sedat Dilek Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ace5e55..64d33d1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2207,10 +2207,6 @@ int hci_register_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - write_lock(&hci_dev_list_lock); - list_add(&hdev->list, &hci_dev_list); - write_unlock(&hci_dev_list_lock); - hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 1); if (!hdev->workqueue) { @@ -2246,6 +2242,10 @@ int hci_register_dev(struct hci_dev *hdev) if (hdev->dev_type != HCI_AMP) set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + write_lock(&hci_dev_list_lock); + list_add(&hdev->list, &hci_dev_list); + write_unlock(&hci_dev_list_lock); + hci_notify(hdev, HCI_DEV_REG); hci_dev_hold(hdev); @@ -2258,9 +2258,6 @@ err_wqueue: destroy_workqueue(hdev->req_workqueue); err: ida_simple_remove(&hci_index_ida, hdev->id); - write_lock(&hci_dev_list_lock); - list_del(&hdev->list); - write_unlock(&hci_dev_list_lock); return error; } -- cgit v0.10.2 From 1d5b569ef85d013a775560a90050dc630614c045 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Thu, 20 Jun 2013 13:38:45 +0800 Subject: Bluetooth: Add support for Atheros [0cf3:e003] Add support for the AR9462 chip T: Bus=02 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=e003 Rev=00.02 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Cc: Stable Signed-off-by: AceLan Kao Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index d3a2d6f..a12b923 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -94,6 +94,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04c5, 0x1330) }, { USB_DEVICE(0x13d3, 0x3402) }, { USB_DEVICE(0x0cf3, 0x3121) }, + { USB_DEVICE(0x0cf3, 0xe003) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -134,6 +135,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index fd5eaa3..5fb06ec 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -154,6 +154,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From 29ed1f29b68a8395d5679b3c4e38352b617b3236 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 19 Jul 2013 12:14:16 -0700 Subject: PCI: pciehp: Fix null pointer deref when hot-removing SR-IOV device Hot-removing a device with SR-IOV enabled causes a null pointer dereference in v3.9 and v3.10. This is a regression caused by ba518e3c17 ("PCI: pciehp: Iterate over all devices in slot, not functions 0-7"). When we iterate over the bus->devices list, we first remove the PF, which also removes all the VFs from the list. Then the list iterator blows up because more than just the current entry was removed from the list. ac205b7bb7 ("PCI: make sriov work with hotplug remove") works around a similar problem in pci_stop_bus_devices() by iterating over the list in reverse, so the VFs are stopped and removed from the list first, before the PF. This patch changes pciehp_unconfigure_device() to iterate over the list in reverse, too. [bhelgaas: bugzilla, changelog] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=60604 Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Yijing Wang CC: stable@vger.kernel.org # v3.9+ diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c index aac7a40..0e0d0f7 100644 --- a/drivers/pci/hotplug/pciehp_pci.c +++ b/drivers/pci/hotplug/pciehp_pci.c @@ -92,7 +92,14 @@ int pciehp_unconfigure_device(struct slot *p_slot) if (ret) presence = 0; - list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { + /* + * Stopping an SR-IOV PF device removes all the associated VFs, + * which will update the bus->devices list and confuse the + * iterator. Therefore, iterate in reverse so we remove the VFs + * first, then the PF. We do the same in pci_stop_bus_device(). + */ + list_for_each_entry_safe_reverse(dev, temp, &parent->devices, + bus_list) { pci_dev_get(dev); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); -- cgit v0.10.2 From 7cd29f4b22be3c3468871f5240621a32d9bc903a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 24 Jul 2013 11:36:31 -0600 Subject: PCI: hotplug: Convert to be builtin only, not modular Convert CONFIG_HOTPLUG_PCI from tristate to bool. This only affects the hotplug core; several of the hotplug drivers can still be modules. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Acked-by: Yinghai Lu diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig index 7913695..efbd292 100644 --- a/arch/ia64/configs/generic_defconfig +++ b/arch/ia64/configs/generic_defconfig @@ -31,7 +31,7 @@ CONFIG_ACPI_FAN=m CONFIG_ACPI_DOCK=y CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_CONTAINER=m -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=m CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig index f8e9133..f64980d 100644 --- a/arch/ia64/configs/gensparse_defconfig +++ b/arch/ia64/configs/gensparse_defconfig @@ -25,7 +25,7 @@ CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_CONTAINER=m -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=m CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig index a5a9e02..0f4e9e4 100644 --- a/arch/ia64/configs/tiger_defconfig +++ b/arch/ia64/configs/tiger_defconfig @@ -31,7 +31,7 @@ CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_CONTAINER=m -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=m CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/ia64/configs/xen_domu_defconfig b/arch/ia64/configs/xen_domu_defconfig index 37b9b42..b025acf 100644 --- a/arch/ia64/configs/xen_domu_defconfig +++ b/arch/ia64/configs/xen_domu_defconfig @@ -32,7 +32,7 @@ CONFIG_ACPI_BUTTON=m CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_CONTAINER=m -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=m CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index c86fcb9..0e8cfd0 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -58,7 +58,7 @@ CONFIG_SCHED_SMT=y CONFIG_PPC_DENORMALISATION=y CONFIG_PCCARD=y CONFIG_ELECTRA_CF=y -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_RPA=m CONFIG_HOTPLUG_PCI_RPA_DLPAR=m CONFIG_PACKET=y diff --git a/arch/powerpc/configs/ppc64e_defconfig b/arch/powerpc/configs/ppc64e_defconfig index 4b20f76..0085dc4 100644 --- a/arch/powerpc/configs/ppc64e_defconfig +++ b/arch/powerpc/configs/ppc64e_defconfig @@ -32,7 +32,7 @@ CONFIG_IRQ_ALL_CPUS=y CONFIG_SPARSEMEM_MANUAL=y CONFIG_PCI_MSI=y CONFIG_PCCARD=y -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_XFRM_USER=m diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index bea8587..1d4b976 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -53,7 +53,7 @@ CONFIG_PPC_64K_PAGES=y CONFIG_PPC_SUBPAGE_PROT=y CONFIG_SCHED_SMT=y CONFIG_PPC_DENORMALISATION=y -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_RPA=m CONFIG_HOTPLUG_PCI_RPA_DLPAR=m CONFIG_PACKET=y diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig index 2051821..0cf4097 100644 --- a/arch/sh/configs/sh03_defconfig +++ b/arch/sh/configs/sh03_defconfig @@ -22,7 +22,7 @@ CONFIG_PREEMPT=y CONFIG_CMDLINE_OVERWRITE=y CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs" CONFIG_PCI=y -CONFIG_HOTPLUG_PCI=m +CONFIG_HOTPLUG_PCI=y CONFIG_BINFMT_MISC=y CONFIG_NET=y CONFIG_PACKET=y diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index bb7ebb2..d85009d 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -3,16 +3,13 @@ # menuconfig HOTPLUG_PCI - tristate "Support for PCI Hotplug" + bool "Support for PCI Hotplug" depends on PCI && SYSFS ---help--- Say Y here if you have a motherboard with a PCI Hotplug controller. This allows you to add and remove PCI cards while the machine is powered up and running. - To compile this driver as a module, choose M here: the - module will be called pci_hotplug. - When in doubt, say N. if HOTPLUG_PCI -- cgit v0.10.2 From bf265c848f162c3189f6e3f0ba619de1a82bcbdc Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 25 Jul 2013 15:45:26 +0200 Subject: video: xilinxfb: Fix compilation warning regs_phys is phys_addr_t (u32 or u64). Lets use %pa printk format specifier. Fixes compilation warning introduced by: video: xilinxfb: Use drvdata->regs_phys instead of physaddr (sha1: c88fafef0135e1e1c3e23c3e32ccbeeabc587f81) Signed-off-by: Michal Simek Reviewed-by: Jingoo Han Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index f3d4a69..6629b29 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -341,8 +341,8 @@ static int xilinxfb_assign(struct platform_device *pdev, if (drvdata->flags & BUS_ACCESS_FLAG) { /* Put a banner in the log (for DEBUG) */ - dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys, - drvdata->regs); + dev_dbg(dev, "regs: phys=%pa, virt=%p\n", + &drvdata->regs_phys, drvdata->regs); } /* Put a banner in the log (for DEBUG) */ dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n", -- cgit v0.10.2 From f64279c8a3597137f6e39a8f3ade9db9d66684e8 Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Wed, 10 Jul 2013 23:57:00 +0100 Subject: vga16fb: Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix build warning of unused variable: drivers/video/vga16fb.c:1268:26: warning: unused variable ‘dev’ [-Wunused-variable] Signed-off-by: Luis Henriques Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 830ded4..2827333 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image static void vga16fb_destroy(struct fb_info *info) { - struct platform_device *dev = container_of(info->device, struct platform_device, dev); iounmap(info->screen_base); fb_dealloc_cmap(&info->cmap); /* XXX unshare VGA regions */ -- cgit v0.10.2 From 8a896baafc951dd97d40a07a1cd1789c1c02c4bf Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 16 Jul 2013 08:07:14 +0800 Subject: video: nuc900fb: fix to pass correct device identity to request_irq() The IRQ handler nuc900fb_irqhandler() use dev_id as a type of struct nuc900fb_info *, so we should pass fbi as the device identity to request_irq(). Signed-off-by: Wei Yongjun Acked-by: Wan Zongshun Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 8c527e5..796e511 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -587,8 +587,7 @@ static int nuc900fb_probe(struct platform_device *pdev) fbinfo->flags = FBINFO_FLAG_DEFAULT; fbinfo->pseudo_palette = &fbi->pseudo_pal; - ret = request_irq(irq, nuc900fb_irqhandler, 0, - pdev->name, fbinfo); + ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi); if (ret) { dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n", irq, ret); -- cgit v0.10.2 From 2997494fa66a1c94717d69c3cfae0a94462093c6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 24 Jul 2013 10:19:06 +0300 Subject: iwlwifi: pcie: reset the NIC before the bring up This allows to clean all kinds of bad state it might be in. This solves situation where HW RFkill was switched while the NIC was offline. Until now, we relied on the firmware to do clean the interrupt, but new firmwares don't do that any more. Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 826c156..96cfcdd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) return err; } + /* Reset the entire device */ + iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + + usleep_range(10, 15); + iwl_pcie_apm_init(trans); /* From now on, the op_mode will be kept updated about RF kill state */ -- cgit v0.10.2 From ea183d02e1ddfda1996d7df1e55f3a639830e335 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 23 Jul 2013 14:41:53 +0300 Subject: iwlwifi: mvm: Disable managed PS when GO is added The managed interface PS was not disabled when a GO interface was added. As a consequence, when the station VMAC was in PS, the GO also was not on the medium. Fix this. Signed-off-by: Ilan Peer Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 1eedc42..f19baf0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -512,6 +512,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; /* + * TODO: remove this temporary code. + * Currently MVM FW supports power management only on single MAC. + * If new interface added, disable PM on existing interface. + * P2P device is a special case, since it is handled by FW similary to + * scan. If P2P deviced is added, PM remains enabled on existing + * interface. + * Note: the method below does not count the new interface being added + * at this moment. + */ + if (vif->type != NL80211_IFTYPE_P2P_DEVICE) + mvm->vif_count++; + if (mvm->vif_count > 1) { + IWL_DEBUG_MAC80211(mvm, + "Disable power on existing interfaces\n"); + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_pm_disable_iterator, mvm); + } + + /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 * start_ap() flow), and adding the broadcast station can happen @@ -534,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; } - /* - * TODO: remove this temporary code. - * Currently MVM FW supports power management only on single MAC. - * If new interface added, disable PM on existing interface. - * P2P device is a special case, since it is handled by FW similary to - * scan. If P2P deviced is added, PM remains enabled on existing - * interface. - * Note: the method below does not count the new interface being added - * at this moment. - */ - if (vif->type != NL80211_IFTYPE_P2P_DEVICE) - mvm->vif_count++; - if (mvm->vif_count > 1) { - IWL_DEBUG_MAC80211(mvm, - "Disable power on existing interfaces\n"); - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_pm_disable_iterator, mvm); - } - ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_release; -- cgit v0.10.2 From b6658ff80c43bcf84be0bbe371c88af1452e7776 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 Jul 2013 13:55:51 +0200 Subject: iwlwifi: mvm: fix flushing not started aggregation sessions When a not fully started aggregation session is destroyed and flushed, we get a warning, e.g. WARNING: at drivers/net/wireless/iwlwifi/pcie/tx.c:1142 iwl_trans_pcie_txq_disable+0x11c/0x160 queue 16 not used Modules linked in: [...] Pid: 5135, comm: hostapd Tainted: G W O 3.5.0 #10 Call Trace: wlan0: driver sets block=0 for sta 00:03:7f:10:44:d3 [] warn_slowpath_common+0x72/0xa0 [] warn_slowpath_fmt+0x47/0x50 [] iwl_trans_pcie_txq_disable+0x11c/0x160 [iwlwifi] [] iwl_mvm_sta_tx_agg_flush+0xe9/0x150 [iwlmvm] [] iwl_mvm_mac_ampdu_action+0xf3/0x1e0 [iwlmvm] [] ___ieee80211_stop_tx_ba_session+0x193/0x920 [mac80211] [] __ieee80211_stop_tx_ba_session+0x48/0x70 [mac80211] [] ieee80211_sta_tear_down_BA_sessions+0x4f/0x80 [mac80211] [] __sta_info_destroy+0x66/0x370 [mac80211] [] sta_info_destroy_addr_bss+0x44/0x70 [mac80211] [] ieee80211_del_station+0x26/0x50 [mac80211] [] nl80211_del_station+0x85/0x200 [cfg80211] when a station deauthenticated from us without fully setting up the aggregation session. Fix this by checking the aggregation state before removing the hardware queue. Cc: stable@vger.kernel.org Reviewed-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 85d4bbe..563f559 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -915,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv; struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; u16 txq_id; + enum iwl_mvm_agg_state old_state; /* * First set the agg state to OFF to avoid calling @@ -924,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, txq_id = tid_data->txq_id; IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n", mvmsta->sta_id, tid, txq_id, tid_data->state); + old_state = tid_data->state; tid_data->state = IWL_AGG_OFF; spin_unlock_bh(&mvmsta->lock); - if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) - IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + if (old_state >= IWL_AGG_ON) { + if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) + IWL_ERR(mvm, "Couldn't flush the AGG queue\n"); + + iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); + } - iwl_trans_txq_disable(mvm->trans, tid_data->txq_id); mvm->queue_to_mac80211[tid_data->txq_id] = IWL_INVALID_MAC80211_QUEUE; -- cgit v0.10.2 From a53ee0a308b16e392e0219c585b10f329345766b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 25 Jul 2013 13:14:34 +0300 Subject: iwlwifi: pcie: clear RFKILL interrupt in AMPG If we forget to do so, we can't send HCMD to firmware while the NIC is in RFKILL state. Cc: stable@vger.kernel.org Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ff8cc75..a70c7b9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -97,6 +97,8 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) +#define APMG_RTC_INT_STT_RFKILL (0x10000000) + /* Device system time */ #define DEVICE_SYSTEM_TIME_REG 0xA0206C diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index fd848cd..f600e68 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); if (hw_rfkill) { + /* + * Clear the interrupt in APMG if the NIC is going down. + * Note that when the NIC exits RFkill (else branch), we + * can't access prph and the NIC will be reset in + * start_hw anyway. + */ + iwl_write_prph(trans, APMG_RTC_INT_STT_REG, + APMG_RTC_INT_STT_RFKILL); set_bit(STATUS_RFKILL, &trans_pcie->status); if (test_and_clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) -- cgit v0.10.2 From 6d3488a5acc64b79773ada12060babe90c0fb130 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 26 Jul 2013 11:27:53 +0300 Subject: fbdev/sgivwfb: fix compilation error in sgivwfb_mmap() Commit c84deb9d615c02993ce0972a0b34585c7624822f ("fbdev/sgivwfb: use vm_iomap_memory()") changed sgivwfb_mmap() to use the new vm_iomap_memory() function. The commit introduced the following compilation error: drivers/video/sgivwfb.c:716:9: note: each undeclared identifier is reported only once for each function it appears in This patch fixes the error. Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index b2a8912..a9ac3ce 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -713,7 +713,7 @@ static int sgivwfb_mmap(struct fb_info *info, r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size); printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", - offset, vma->vm_start); + sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start); return r; } -- cgit v0.10.2 From 8fbac214e5c594a0c2fe78c14adf2cdbb1febc92 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 18 Jul 2013 17:20:33 +0100 Subject: ARM: 7787/1: virt: ensure visibility of __boot_cpu_mode Secondary CPUs write to __boot_cpu_mode with caches disabled, and thus a cached value of __boot_cpu_mode may be incoherent with that in memory. This could lead to a failure to detect mismatched boot modes. This patch adds flushing to ensure that writes by secondaries to __boot_cpu_mode are made visible before we test against it. Signed-off-by: Mark Rutland Acked-by: Dave Martin Acked-by: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Russell King diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h index 50af92b..4371f45 100644 --- a/arch/arm/include/asm/virt.h +++ b/arch/arm/include/asm/virt.h @@ -29,6 +29,7 @@ #define BOOT_CPU_MODE_MISMATCH PSR_N_BIT #ifndef __ASSEMBLY__ +#include #ifdef CONFIG_ARM_VIRT_EXT /* @@ -41,10 +42,21 @@ */ extern int __boot_cpu_mode; +static inline void sync_boot_mode(void) +{ + /* + * As secondaries write to __boot_cpu_mode with caches disabled, we + * must flush the corresponding cache entries to ensure the visibility + * of their writes. + */ + sync_cache_r(&__boot_cpu_mode); +} + void __hyp_set_vectors(unsigned long phys_vector_base); unsigned long __hyp_get_vectors(void); #else #define __boot_cpu_mode (SVC_MODE) +#define sync_boot_mode() #endif #ifndef ZIMAGE diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 96286cb..afc2489 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -836,6 +836,8 @@ static int __init meminfo_cmp(const void *_a, const void *_b) void __init hyp_mode_check(void) { #ifdef CONFIG_ARM_VIRT_EXT + sync_boot_mode(); + if (is_hyp_mode_available()) { pr_info("CPU: All CPU(s) started in HYP mode.\n"); pr_info("CPU: Virtualization extensions available.\n"); -- cgit v0.10.2 From 1f49856bb029779d8f1b63517a3a3b34ffe672c7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 23 Jul 2013 15:13:06 +0100 Subject: ARM: 7789/1: Do not run dummy_flush_tlb_a15_erratum() on non-Cortex-A15 Commit 93dc688 (ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations)) causes the following undefined instruction error on a mx53 (Cortex-A8): Internal error: Oops - undefined instruction: 0 [#1] SMP ARM CPU: 0 PID: 275 Comm: modprobe Not tainted 3.11.0-rc2-next-20130722-00009-g9b0f371 #881 task: df46cc00 ti: df48e000 task.ti: df48e000 PC is at check_and_switch_context+0x17c/0x4d0 LR is at check_and_switch_context+0xdc/0x4d0 This problem happens because check_and_switch_context() calls dummy_flush_tlb_a15_erratum() without checking if we are really running on a Cortex-A15 or not. To avoid this issue, only call dummy_flush_tlb_a15_erratum() inside check_and_switch_context() if erratum_a15_798181() returns true, which means that we are really running on a Cortex-A15. Signed-off-by: Fabio Estevam Acked-by: Catalin Marinas Reviewed-by: Roger Quadros Signed-off-by: Russell King diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index fdbb9e3..f467e9b 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -443,7 +443,18 @@ static inline void local_flush_bp_all(void) isb(); } +#include #ifdef CONFIG_ARM_ERRATA_798181 +static inline int erratum_a15_798181(void) +{ + unsigned int midr = read_cpuid_id(); + + /* Cortex-A15 r0p0..r3p2 affected */ + if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2) + return 0; + return 1; +} + static inline void dummy_flush_tlb_a15_erratum(void) { /* @@ -453,6 +464,11 @@ static inline void dummy_flush_tlb_a15_erratum(void) dsb(); } #else +static inline int erratum_a15_798181(void) +{ + return 0; +} + static inline void dummy_flush_tlb_a15_erratum(void) { } diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c index a98b62d..c2edfff 100644 --- a/arch/arm/kernel/smp_tlb.c +++ b/arch/arm/kernel/smp_tlb.c @@ -70,23 +70,6 @@ static inline void ipi_flush_bp_all(void *ignored) local_flush_bp_all(); } -#ifdef CONFIG_ARM_ERRATA_798181 -static int erratum_a15_798181(void) -{ - unsigned int midr = read_cpuid_id(); - - /* Cortex-A15 r0p0..r3p2 affected */ - if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2) - return 0; - return 1; -} -#else -static int erratum_a15_798181(void) -{ - return 0; -} -#endif - static void ipi_flush_tlb_a15_erratum(void *arg) { dmb(); diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index b55b101..4a05444 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -245,7 +245,8 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) { local_flush_bp_all(); local_flush_tlb_all(); - dummy_flush_tlb_a15_erratum(); + if (erratum_a15_798181()) + dummy_flush_tlb_a15_erratum(); } atomic64_set(&per_cpu(active_asids, cpu), asid); -- cgit v0.10.2 From bdae73cd374e28db544fdd9b77de689a36e3c129 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 23 Jul 2013 16:15:36 +0100 Subject: ARM: 7790/1: Fix deferred mm switch on VIVT processors As of commit b9d4d42ad9 (ARM: Remove __ARCH_WANT_INTERRUPTS_ON_CTXSW on pre-ARMv6 CPUs), the mm switching on VIVT processors is done in the finish_arch_post_lock_switch() function to avoid whole cache flushing with interrupts disabled. The need for deferred mm switch is stored as a thread flag (TIF_SWITCH_MM). However, with preemption enabled, we can have another thread switch before finish_arch_post_lock_switch(). If the new thread has the same mm as the previous 'next' thread, the scheduler will not call switch_mm() and the TIF_SWITCH_MM flag won't be set for the new thread. This patch moves the switch pending flag to the mm_context_t structure since this is specific to the mm rather than thread. Signed-off-by: Catalin Marinas Reported-by: Marc Kleine-Budde Tested-by: Marc Kleine-Budde Cc: # 3.5+ Signed-off-by: Russell King diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index e3d5554..d1b4998 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -6,6 +6,8 @@ typedef struct { #ifdef CONFIG_CPU_HAS_ASID atomic64_t id; +#else + int switch_pending; #endif unsigned int vmalloc_seq; } mm_context_t; diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index b5792b7..9b32f76 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h @@ -56,7 +56,7 @@ static inline void check_and_switch_context(struct mm_struct *mm, * on non-ASID CPUs, the old mm will remain valid until the * finish_arch_post_lock_switch() call. */ - set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); + mm->context.switch_pending = 1; else cpu_switch_mm(mm->pgd, mm); } @@ -65,9 +65,21 @@ static inline void check_and_switch_context(struct mm_struct *mm, finish_arch_post_lock_switch static inline void finish_arch_post_lock_switch(void) { - if (test_and_clear_thread_flag(TIF_SWITCH_MM)) { - struct mm_struct *mm = current->mm; - cpu_switch_mm(mm->pgd, mm); + struct mm_struct *mm = current->mm; + + if (mm && mm->context.switch_pending) { + /* + * Preemption must be disabled during cpu_switch_mm() as we + * have some stateful cache flush implementations. Check + * switch_pending again in case we were preempted and the + * switch to this mm was already done. + */ + preempt_disable(); + if (mm->context.switch_pending) { + mm->context.switch_pending = 0; + cpu_switch_mm(mm->pgd, mm); + } + preempt_enable_no_resched(); } } diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 214d415..2b8114f 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -156,7 +156,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20 -#define TIF_SWITCH_MM 22 /* deferred switch_mm */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) -- cgit v0.10.2 From acfdd4b1f7590d02e9bae3b73bdbbc4a31b05d38 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 25 Jul 2013 11:44:48 +0100 Subject: ARM: 7791/1: a.out: remove partial a.out support a.out support on ARM requires that argc, argv and envp are passed in r0-r2 respectively, which requires hacking load_aout_binary to prevent argc being clobbered by the return code. Whilst mainline kernels do set the registers up in start_thread, the aout loader has never carried the hack in mainline. Initialising the registers in this way actually goes against the libc expectations for ELF binaries, where argc, argv and envp are passed on the stack, with r0 being used to hold a pointer to an exit function for cleaning up after the dynamic linker if required. If the pointer is NULL, then it is ignored. When execing an ELF binary, Linux currently zeroes r0, then sets it to argc and then finally clobbers it with the return value of the execve syscall, so we actually end up with: r0 = 0 stack[0] = argc r1 = stack[1] = argv r2 = stack[2] = envp libc treats r1 and r2 as undefined. The clobbering of r0 by sys_execve works for user-spawned threads, but when executing an ELF binary from a kernel thread (via call_usermodehelper), the execve is performed on the ret_from_fork path, which restores r0 from the saved pt_regs, resulting in argc being presented to the C library. This has horrible consequences when the application exits, since we have an exit function registered using argc, resulting in a jump to hyperspace. This patch solves the problem by removing the partial a.out support from arch/arm/ altogether. Cc: Cc: Ashish Sangwan Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e0..82f06982 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -20,7 +20,6 @@ config ARM select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select HARDIRQS_SW_RESEND - select HAVE_AOUT select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB select HAVE_ARCH_SECCOMP_FILTER diff --git a/arch/arm/include/asm/a.out-core.h b/arch/arm/include/asm/a.out-core.h deleted file mode 100644 index 92f10cb..0000000 --- a/arch/arm/include/asm/a.out-core.h +++ /dev/null @@ -1,45 +0,0 @@ -/* a.out coredump register dumper - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#ifndef _ASM_A_OUT_CORE_H -#define _ASM_A_OUT_CORE_H - -#ifdef __KERNEL__ - -#include -#include - -/* - * fill in the user structure for an a.out core dump - */ -static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump) -{ - struct task_struct *tsk = current; - - dump->magic = CMAGIC; - dump->start_code = tsk->mm->start_code; - dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); - - dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT; - dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; - dump->u_ssize = 0; - - memset(dump->u_debugreg, 0, sizeof(dump->u_debugreg)); - - if (dump->start_stack < 0x04000000) - dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; - - dump->regs = *regs; - dump->u_fpvalid = dump_fpu (regs, &dump->u_fp); -} - -#endif /* __KERNEL__ */ -#endif /* _ASM_A_OUT_CORE_H */ diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h index 06e7d50..413f387 100644 --- a/arch/arm/include/asm/processor.h +++ b/arch/arm/include/asm/processor.h @@ -54,7 +54,6 @@ struct thread_struct { #define start_thread(regs,pc,sp) \ ({ \ - unsigned long *stack = (unsigned long *)sp; \ memset(regs->uregs, 0, sizeof(regs->uregs)); \ if (current->personality & ADDR_LIMIT_32BIT) \ regs->ARM_cpsr = USR_MODE; \ @@ -65,9 +64,6 @@ struct thread_struct { regs->ARM_cpsr |= PSR_ENDSTATE; \ regs->ARM_pc = pc & ~1; /* pc */ \ regs->ARM_sp = sp; /* sp */ \ - regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ - regs->ARM_r1 = stack[1]; /* r1 (argv) */ \ - regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ nommu_start_thread(regs); \ }) diff --git a/arch/arm/include/uapi/asm/Kbuild b/arch/arm/include/uapi/asm/Kbuild index 47bcb2d..18d76fd 100644 --- a/arch/arm/include/uapi/asm/Kbuild +++ b/arch/arm/include/uapi/asm/Kbuild @@ -1,7 +1,6 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm -header-y += a.out.h header-y += byteorder.h header-y += fcntl.h header-y += hwcap.h diff --git a/arch/arm/include/uapi/asm/a.out.h b/arch/arm/include/uapi/asm/a.out.h deleted file mode 100644 index 083894b..0000000 --- a/arch/arm/include/uapi/asm/a.out.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __ARM_A_OUT_H__ -#define __ARM_A_OUT_H__ - -#include -#include - -struct exec -{ - __u32 a_info; /* Use macros N_MAGIC, etc for access */ - __u32 a_text; /* length of text, in bytes */ - __u32 a_data; /* length of data, in bytes */ - __u32 a_bss; /* length of uninitialized data area for file, in bytes */ - __u32 a_syms; /* length of symbol table data in file, in bytes */ - __u32 a_entry; /* start address */ - __u32 a_trsize; /* length of relocation info for text, in bytes */ - __u32 a_drsize; /* length of relocation info for data, in bytes */ -}; - -/* - * This is always the same - */ -#define N_TXTADDR(a) (0x00008000) - -#define N_TRSIZE(a) ((a).a_trsize) -#define N_DRSIZE(a) ((a).a_drsize) -#define N_SYMSIZE(a) ((a).a_syms) - -#define M_ARM 103 - -#ifndef LIBRARY_START_TEXT -#define LIBRARY_START_TEXT (0x00c00000) -#endif - -#endif /* __A_OUT_GNU_H__ */ -- cgit v0.10.2 From c10cc483bf3f1d0e8f9f077ca36ecc053de9bbbc Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 23 Jul 2013 10:55:56 -0600 Subject: PCI: pciehp: Convert pciehp to be builtin only, not modular Convert pciehp to be builtin only, with no module option. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki Acked-by: Yinghai Lu diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 569f82f..3b94cfc 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -14,15 +14,12 @@ config PCIEPORTBUS # Include service Kconfig here # config HOTPLUG_PCI_PCIE - tristate "PCI Express Hotplug driver" + bool "PCI Express Hotplug driver" depends on HOTPLUG_PCI && PCIEPORTBUS help Say Y here if you have a motherboard that supports PCI Express Native Hotplug - To compile this driver as a module, choose M here: the - module will be called pciehp. - When in doubt, say N. source "drivers/pci/pcie/aer/Kconfig" -- cgit v0.10.2 From aa914f5ec25e4371ba18b312971314be1b9b1076 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 25 Jul 2013 06:31:38 -0700 Subject: PCI: Retry allocation of only the resource type that failed Ben Herrenschmidt reported the following problem: - The bus has space for all desired MMIO resources, including optional space for SR-IOV devices - We attempt to allocate I/O port space, but it fails because the bus has no I/O space - Because of the I/O allocation failure, we retry MMIO allocation, requesting only the required space, without the optional SR-IOV space This means we don't allocate the optional SR-IOV space, even though we could. This is related to 0c5be0cb0e ("PCI: Retry on IORESOURCE_IO type allocations"). This patch changes how we handle allocation failures. We will now retry allocation of only the resource type that failed. If MMIO allocation fails, we'll retry only MMIO allocation. If I/O port allocation fails, we'll retry only I/O port allocation. [bhelgaas: changelog] Reference: https://lkml.kernel.org/r/1367712653.11982.19.camel@pasglop Reported-by: Benjamin Herrenschmidt Tested-by: Gavin Shan Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas CC: stable@vger.kernel.org # v3.10+ diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index d254e23..64a7de2 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head, } } +static unsigned long pci_fail_res_type_mask(struct list_head *fail_head) +{ + struct pci_dev_resource *fail_res; + unsigned long mask = 0; + + /* check failed type */ + list_for_each_entry(fail_res, fail_head, list) + mask |= fail_res->flags; + + /* + * one pref failed resource will set IORESOURCE_MEM, + * as we can allocate pref in non-pref range. + * Will release all assigned non-pref sibling resources + * according to that bit. + */ + return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH); +} + +static bool pci_need_to_release(unsigned long mask, struct resource *res) +{ + if (res->flags & IORESOURCE_IO) + return !!(mask & IORESOURCE_IO); + + /* check pref at first */ + if (res->flags & IORESOURCE_PREFETCH) { + if (mask & IORESOURCE_PREFETCH) + return true; + /* count pref if its parent is non-pref */ + else if ((mask & IORESOURCE_MEM) && + !(res->parent->flags & IORESOURCE_PREFETCH)) + return true; + else + return false; + } + + if (res->flags & IORESOURCE_MEM) + return !!(mask & IORESOURCE_MEM); + + return false; /* should not get here */ +} + static void __assign_resources_sorted(struct list_head *head, struct list_head *realloc_head, struct list_head *fail_head) @@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head, * if could do that, could get out early. * if could not do that, we still try to assign requested at first, * then try to reassign add_size for some resources. + * + * Separate three resource type checking if we need to release + * assigned resource after requested + add_size try. + * 1. if there is io port assign fail, will release assigned + * io port. + * 2. if there is pref mmio assign fail, release assigned + * pref mmio. + * if assigned pref mmio's parent is non-pref mmio and there + * is non-pref mmio assign fail, will release that assigned + * pref mmio. + * 3. if there is non-pref mmio assign fail or pref mmio + * assigned fail, will release assigned non-pref mmio. */ LIST_HEAD(save_head); LIST_HEAD(local_fail_head); struct pci_dev_resource *save_res; - struct pci_dev_resource *dev_res; + struct pci_dev_resource *dev_res, *tmp_res; + unsigned long fail_type; /* Check if optional add_size is there */ if (!realloc_head || list_empty(realloc_head)) @@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head, return; } + /* check failed type */ + fail_type = pci_fail_res_type_mask(&local_fail_head); + /* remove not need to be released assigned res from head list etc */ + list_for_each_entry_safe(dev_res, tmp_res, head, list) + if (dev_res->res->parent && + !pci_need_to_release(fail_type, dev_res->res)) { + /* remove it from realloc_head list */ + remove_from_list(realloc_head, dev_res->res); + remove_from_list(&save_head, dev_res->res); + list_del(&dev_res->list); + kfree(dev_res); + } + free_list(&local_fail_head); /* Release assigned resource */ list_for_each_entry(dev_res, head, list) -- cgit v0.10.2 From 3606b99971b66b57a68c952619b43c12f90d2c70 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 26 Jul 2013 10:00:45 -0700 Subject: RDMA/ocrdma: Remove unused include I'd like to remove rdma/ib_cache.h some day, so let's avoid proliferating uses of it unnecessarily. Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c index a877a8e..f4c587c 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c @@ -29,7 +29,6 @@ #include #include -#include #include "ocrdma.h" #include "ocrdma_verbs.h" -- cgit v0.10.2 From 20f0170377264e8449b6987041f0bcc4d746d3ed Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 23 Jul 2013 17:15:54 -0700 Subject: usbnet: do not pretend to support SG/TSO usbnet doesn't support yet SG, so drivers should not advertise SG or TSO capabilities, as they allow TCP stack to build large TSO packets that need to be linearized and might use order-5 pages. This adds an extra copy overhead and possible allocation failures. Current code ignore skb_linearize() return code so crashes are even possible. Best is to not pretend SG/TSO is supported, and add this again when/if usbnet really supports SG for devices who could get a performance gain. Based on a prior patch from Freddy Xin Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 1e3c302..2bc87e3 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1029,10 +1029,10 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.supports_gmii = 1; dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; /* Enable checksum offload */ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | @@ -1173,7 +1173,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) if (((skb->len + 8) % frame_size) == 0) tx_hdr2 |= 0x80008000; /* Enable padding */ - skb_linearize(skb); headroom = skb_headroom(skb); tailroom = skb_tailroom(skb); @@ -1317,10 +1316,10 @@ static int ax88179_reset(struct usbnet *dev) 1, 1, tmp); dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO; + NETIF_F_RXCSUM; /* Enable checksum offload */ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 7540974..66ebbac 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -45,7 +45,6 @@ #define EEPROM_MAC_OFFSET (0x01) #define DEFAULT_TX_CSUM_ENABLE (true) #define DEFAULT_RX_CSUM_ENABLE (true) -#define DEFAULT_TSO_ENABLE (true) #define SMSC75XX_INTERNAL_PHY_ID (1) #define SMSC75XX_TX_OVERHEAD (8) #define MAX_RX_FIFO_SIZE (20 * 1024) @@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); - if (DEFAULT_TX_CSUM_ENABLE) { + if (DEFAULT_TX_CSUM_ENABLE) dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - if (DEFAULT_TSO_ENABLE) - dev->net->features |= NETIF_F_SG | - NETIF_F_TSO | NETIF_F_TSO6; - } + if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM; + NETIF_F_RXCSUM; ret = smsc75xx_wait_ready(dev, 0); if (ret < 0) { @@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, { u32 tx_cmd_a, tx_cmd_b; - skb_linearize(skb); - if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { struct sk_buff *skb2 = skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); -- cgit v0.10.2 From 05bc250fe623e61e132dc1f771fca0a842ea60b6 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 24 Jul 2013 09:11:37 +0200 Subject: drivers: net: allwinner: Fix Kconfig indentation Signed-off-by: Maxime Ripard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index 53ad213..cf7aa24 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -3,19 +3,20 @@ # config NET_VENDOR_ALLWINNER - bool "Allwinner devices" - default y - depends on ARCH_SUNXI - ---help--- - If you have a network (Ethernet) card belonging to this - class, say Y and read the Ethernet-HOWTO, available from - . + bool "Allwinner devices" + default y - Note that the answer to this question doesn't directly - affect the kernel: saying N will just cause the configurator - to skip all the questions about Allwinner cards. If you say Y, - you will be asked for your specific card in the following - questions. + depends on ARCH_SUNXI + ---help--- + If you have a network (Ethernet) card belonging to this + class, say Y and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly + affect the kernel: saying N will just cause the configurator + to skip all the questions about Allwinner cards. If you say Y, + you will be asked for your specific card in the following + questions. if NET_VENDOR_ALLWINNER -- cgit v0.10.2 From 111cc5da2a95568ca20a5f86f43ae328c069e455 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 24 Jul 2013 09:12:08 +0200 Subject: drivers: net: sun4i-emac: select MDIO_SUN4I The EMAC driver can't work without its associated PHY driver. Reflect this in the Kconfig options by selecting it. Signed-off-by: Maxime Ripard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index cf7aa24..d8d95d4 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -27,6 +27,7 @@ config SUN4I_EMAC select CRC32 select MII select PHYLIB + select MDIO_SUN4I ---help--- Support for Allwinner A10 EMAC ethernet driver. -- cgit v0.10.2 From 83e612f632c3897be29ef02e0472f6d63e258378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mo=C5=84?= Date: Tue, 23 Jul 2013 07:42:49 +0200 Subject: mwifiex: Add missing endian conversion. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both type and pkt_len variables are in host endian and these should be in Little Endian in the payload. Signed-off-by: Tomasz Moń Acked-by: Bing Zhao Cc: Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 5ef49f2..09185c9 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1639,8 +1639,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, /* Allocate buffer and copy payload */ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; buf_block_len = (pkt_len + blk_size - 1) / blk_size; - *(u16 *) &payload[0] = (u16) pkt_len; - *(u16 *) &payload[2] = type; + *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len); + *(__le16 *)&payload[2] = cpu_to_le16(type); /* * This is SDIO specific header -- cgit v0.10.2 From a538ae3189a9fa4095ca58c14bc6593622c89ab9 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 25 Jul 2013 23:01:34 +0200 Subject: brcmfmac: inform cfg80211 about disconnect when device is unplugged When the brcmfmac device is physically removed cfg80211 gives a warning upon unregistering the net device (see below). [23052.390197] WARNING: CPU: 0 PID: 30 at net/wireless/core.c:937 cfg80211_netdev_notifier_call+0x164/0x600 [cfg80211]() [23052.400843] Modules linked in: brcmfmac(O) brcmutil(O) cfg80211(O) pl2303 usbserial binfmt_misc snd_hda_codec_hdmi snd_hda_codec_idt snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event lpc_ich snd_seq snd_timer snd_seq_device snd psmouse mfd_core serio_raw soundcore snd_page_alloc intel_ips dell_laptop dell_wmi sparse_keymap dcdbas nouveau ttm drm_kms_helper drm i2c_algo_bit mxm_wmi ahci libahci sdhci_pci firewire_ohci firewire_core sdhci crc_itu_t mmc_core intel_agp intel_gtt e1000e ptp pps_core agpgart video [last unloaded: brcmfmac] [23052.452987] CPU: 0 PID: 30 Comm: khubd Tainted: G O 3.11.0-rc1-wl-testing-lockdep-00002-g41cc093-dirty #1 [23052.463480] Hardware name: Dell Inc. Latitude E6410/07XJP9, BIOS A07 02/15/2011 [23052.470852] 00000000 00000000 f4efdc18 c1522e3d f845bed2 f4efdc48 c103fbe4 c16a9254 [23052.478762] 00000000 0000001e f845bed2 000003a9 f841da44 f841da44 f3790004 f25539c0 [23052.486741] e2700200 f4efdc58 c103fc22 00000009 00000000 f4efdcc0 f841da44 00000002 [23052.494712] Call Trace: [23052.497165] [] dump_stack+0x4b/0x66 [23052.501685] [] warn_slowpath_common+0x84/0xa0 [23052.507085] [] ? cfg80211_netdev_notifier_call+0x164/0x600 [cfg80211] [23052.514542] [] ? cfg80211_netdev_notifier_call+0x164/0x600 [cfg80211] [23052.521981] [] warn_slowpath_null+0x22/0x30 [23052.527191] [] cfg80211_netdev_notifier_call+0x164/0x600 [cfg80211] [23052.534494] [] ? packet_notifier+0xc8/0x1d0 [23052.539703] [] ? packet_notifier+0xdc/0x1d0 [23052.544880] [] ? packet_seq_stop+0x30/0x30 [23052.550002] [] notifier_call_chain+0x45/0x60 [23052.555298] [] raw_notifier_call_chain+0x1f/0x30 [23052.560963] [] call_netdevice_notifiers_info+0x33/0x70 [23052.567153] [] ? qdisc_destroy+0x99/0xb0 [23052.572116] [] call_netdevice_notifiers+0x13/0x20 [23052.577861] [] rollback_registered_many+0xf3/0x1d0 [23052.583687] [] ? mutex_lock_nested+0x25c/0x350 [23052.589150] [] rollback_registered+0x24/0x40 [23052.594445] [] unregister_netdevice_queue+0x4f/0xb0 [23052.600344] [] unregister_netdev+0x19/0x30 [23052.605484] [] brcmf_del_if+0xbf/0x160 [brcmfmac] [23052.611223] [] brcmf_detach+0x5e/0xd0 [brcmfmac] [23052.616881] [] brcmf_usb_disconnect+0x63/0xa0 [brcmfmac] [23052.623217] [] usb_unbind_interface+0x4a/0x180 When the device is physically connected the driver sends a disassoc command to the device and response triggers the driver to inform cfg80211 about it. However, with the device removed the disassoc command fails. This patch adds a call to cfg80211_disconnected() when that command fails. The warning was added by commit below and also cleans up, but better doing it in the driver if only to get rid of the warning. commit f9bef3df52fe61067e4c1c6cfb2037cb6b259a6a Author: Ben Greear Date: Wed Jun 19 14:06:26 2013 -0700 wireless: check for dangling wdev->current_bss pointer Cc: Ben Greear Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 277b37a..7fa71f7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n "); err = brcmf_fil_cmd_data_set(vif->ifp, BRCMF_C_DISASSOC, NULL, 0); - if (err) + if (err) { brcmf_err("WLC_DISASSOC failed (%d)\n", err); + cfg80211_disconnected(vif->wdev.netdev, 0, + NULL, 0, GFP_KERNEL); + } clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); -- cgit v0.10.2 From a8825734e9169ddd0a2a343ceb8ce7d3ecfa08a7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 25 Jul 2013 21:52:29 -0700 Subject: USB: serial: add driver for Suunto ANT+ USB device This adds a driver for the Suunto ANT+ USB device, exposing it as a usb serial device. This lets the userspace "gant" program to talk to the device to communicate over the ANT+ protocol to any devices it finds. Reported-by: Steinar Gunderson Tested-by: Steinar Gunderson Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 8c3a42e..7eef9b3 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -719,6 +719,13 @@ config USB_SERIAL_FLASHLOADER To compile this driver as a module, choose M here: the module will be called flashloader. +config USB_SERIAL_SUUNTO + tristate "USB Suunto ANT+ driver" + help + Say Y here if you want to use the Suunto ANT+ USB device. + + To compile this driver as a module, choose M here: the + module will be called suunto. config USB_SERIAL_DEBUG tristate "USB Debugging Device" diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index f713011..a14a870 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o +obj-$(CONFIG_USB_SERIAL_SUUNTO) += suunto.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c new file mode 100644 index 0000000..2248e7a --- /dev/null +++ b/drivers/usb/serial/suunto.c @@ -0,0 +1,41 @@ +/* + * Suunto ANT+ USB Driver + * + * Copyright (C) 2013 Greg Kroah-Hartman + * Copyright (C) 2013 Linux Foundation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation only. + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x0fcf, 0x1008) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_serial_driver suunto_device = { + .driver = { + .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + }, + .id_table = id_table, + .num_ports = 1, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &suunto_device, + NULL, +}; + +module_usb_serial_driver(serial_drivers, id_table); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d8a083cc746664916d9d36ed9e4d08a29525f245 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Jul 2013 11:55:17 +0200 Subject: USB: mos7840: fix race in register handling Fix race in mos7840_get_reg which unconditionally manipulated the control urb (which may already be in use) by adding a control-urb busy flag. Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 603fb70..73dda1c 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -183,6 +183,10 @@ #define LED_ON_MS 500 #define LED_OFF_MS 500 +enum mos7840_flag { + MOS7840_FLAG_CTRL_BUSY, +}; + static int device_type; static const struct usb_device_id id_table[] = { @@ -241,6 +245,8 @@ struct moschip_port { bool led_flag; struct timer_list led_timer1; /* Timer for LED on */ struct timer_list led_timer2; /* Timer for LED off */ + + unsigned long flags; }; /* @@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); - return; + goto out; default: dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); - return; + goto out; } dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); @@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb) mos7840_handle_new_msr(mos7840_port, regval); else if (mos7840_port->MsrLsr == 1) mos7840_handle_new_lsr(mos7840_port, regval); +out: + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); } static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, @@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, unsigned char *buffer = mcs->ctrl_buf; int ret; + if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) + return -EBUSY; + dr->bRequestType = MCS_RD_RTYPE; dr->bRequest = MCS_RDREQ; dr->wValue = cpu_to_le16(Wval); /* 0 */ @@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, mos7840_control_callback, mcs); mcs->control_urb->transfer_buffer_length = 2; ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); + if (ret) + clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); + return ret; } -- cgit v0.10.2 From 40c24f2893ba0ba7df485871f6aac0c197ceef5b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Jul 2013 11:55:18 +0200 Subject: USB: mos7840: fix device-type detection Fix race in device-type detection introduced by commit 0eafe4de ("USB: serial: mos7840: add support for MCS7810 devices") which used a static variable to hold the device type. Move type detection to probe and use serial data to store the device type. Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 73dda1c..e95d914 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -187,8 +187,6 @@ enum mos7840_flag { MOS7840_FLAG_CTRL_BUSY, }; -static int device_type; - static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, @@ -830,18 +828,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) /************************************************************************/ /* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ /************************************************************************/ -#ifdef MCSSerialProbe -static int mos7840_serial_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - - /*need to implement the mode_reg reading and updating\ - structures usb_serial_ device_type\ - (i.e num_ports, num_bulkin,bulkout etc) */ - /* Also we can update the changes attach */ - return 1; -} -#endif /***************************************************************************** * mos7840_open @@ -2201,38 +2187,48 @@ static int mos7810_check(struct usb_serial *serial) return 0; } -static int mos7840_calc_num_ports(struct usb_serial *serial) +static int mos7840_probe(struct usb_serial *serial, + const struct usb_device_id *id) { - __u16 data = 0x00; + u16 product = serial->dev->descriptor.idProduct; u8 *buf; - int mos7840_num_ports; + int device_type; + + if (product == MOSCHIP_DEVICE_ID_7810 || + product == MOSCHIP_DEVICE_ID_7820) { + device_type = product; + goto out; + } buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); - if (buf) { - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + if (!buf) + return -ENOMEM; + + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - data = *buf; - kfree(buf); - } - if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || - serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { - device_type = serial->dev->descriptor.idProduct; - } else { - /* For a MCS7840 device GPIO0 must be set to 1 */ - if ((data & 0x01) == 1) - device_type = MOSCHIP_DEVICE_ID_7840; - else if (mos7810_check(serial)) - device_type = MOSCHIP_DEVICE_ID_7810; - else - device_type = MOSCHIP_DEVICE_ID_7820; - } + /* For a MCS7840 device GPIO0 must be set to 1 */ + if (buf[0] & 0x01) + device_type = MOSCHIP_DEVICE_ID_7840; + else if (mos7810_check(serial)) + device_type = MOSCHIP_DEVICE_ID_7810; + else + device_type = MOSCHIP_DEVICE_ID_7820; + + kfree(buf); +out: + usb_set_serial_data(serial, (void *)device_type); + + return 0; +} + +static int mos7840_calc_num_ports(struct usb_serial *serial) +{ + int device_type = (int)usb_get_serial_data(serial); + int mos7840_num_ports; mos7840_num_ports = (device_type >> 4) & 0x000F; - serial->num_bulk_in = mos7840_num_ports; - serial->num_bulk_out = mos7840_num_ports; - serial->num_ports = mos7840_num_ports; return mos7840_num_ports; } @@ -2240,6 +2236,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; + int device_type = (int)usb_get_serial_data(serial); struct moschip_port *mos7840_port; int status; int pnum; @@ -2496,9 +2493,7 @@ static struct usb_serial_driver moschip7840_4port_device = { .throttle = mos7840_throttle, .unthrottle = mos7840_unthrottle, .calc_num_ports = mos7840_calc_num_ports, -#ifdef MCSSerialProbe - .probe = mos7840_serial_probe, -#endif + .probe = mos7840_probe, .ioctl = mos7840_ioctl, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, -- cgit v0.10.2 From 05cf0dec5ccc696a7636c84b265b477173498156 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 26 Jul 2013 11:55:19 +0200 Subject: USB: mos7840: fix race in led handling Fix race in LED handling introduced by commit 0eafe4de ("USB: serial: mos7840: add support for MCS7810 devices") which reused the port control urb for manipulating the LED without making sure that the urb is not already in use. This could lead to the control urb being manipulated while in flight. Fix by adding a dedicated LED urb and ctrlrequest along with a LED-busy flag to handle concurrency. Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index e95d914..c10fc15 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -185,6 +185,7 @@ enum mos7840_flag { MOS7840_FLAG_CTRL_BUSY, + MOS7840_FLAG_LED_BUSY, }; static const struct usb_device_id id_table[] = { @@ -240,9 +241,10 @@ struct moschip_port { /* For device(s) with LED indicator */ bool has_led; - bool led_flag; struct timer_list led_timer1; /* Timer for LED on */ struct timer_list led_timer2; /* Timer for LED off */ + struct urb *led_urb; + struct usb_ctrlrequest *led_dr; unsigned long flags; }; @@ -535,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, __u16 reg) { struct usb_device *dev = mcs->port->serial->dev; - struct usb_ctrlrequest *dr = mcs->dr; + struct usb_ctrlrequest *dr = mcs->led_dr; dr->bRequestType = MCS_WR_RTYPE; dr->bRequest = MCS_WRREQ; @@ -543,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, dr->wIndex = cpu_to_le16(reg); dr->wLength = cpu_to_le16(0); - usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), + usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0), (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); - usb_submit_urb(mcs->control_urb, GFP_ATOMIC); + usb_submit_urb(mcs->led_urb, GFP_ATOMIC); } static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, @@ -572,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg) { struct moschip_port *mcs = (struct moschip_port *) arg; - mcs->led_flag = false; + clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags); +} + +static void mos7840_led_activity(struct usb_serial_port *port) +{ + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); + + if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags)) + return; + + mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); } /***************************************************************************** @@ -770,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } - /* Turn on LED */ - if (mos7840_port->has_led && !mos7840_port->led_flag) { - mos7840_port->led_flag = true; - mos7840_set_led_async(mos7840_port, 0x0301, - MODEM_CONTROL_REGISTER); - mod_timer(&mos7840_port->led_timer1, - jiffies + msecs_to_jiffies(LED_ON_MS)); - } + if (mos7840_port->has_led) + mos7840_led_activity(port); mos7840_port->read_urb_busy = true; retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); @@ -1454,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, data1 = urb->transfer_buffer; dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress); - /* Turn on LED */ - if (mos7840_port->has_led && !mos7840_port->led_flag) { - mos7840_port->led_flag = true; - mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); - mod_timer(&mos7840_port->led_timer1, - jiffies + msecs_to_jiffies(LED_ON_MS)); - } + if (mos7840_port->has_led) + mos7840_led_activity(port); /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); @@ -2412,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port) if (device_type == MOSCHIP_DEVICE_ID_7810) { mos7840_port->has_led = true; + mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL); + mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr), + GFP_KERNEL); + if (!mos7840_port->led_urb || !mos7840_port->led_dr) { + status = -ENOMEM; + goto error; + } + init_timer(&mos7840_port->led_timer1); mos7840_port->led_timer1.function = mos7840_led_off; mos7840_port->led_timer1.expires = @@ -2424,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port) jiffies + msecs_to_jiffies(LED_OFF_MS); mos7840_port->led_timer2.data = (unsigned long)mos7840_port; - mos7840_port->led_flag = false; - /* Turn off LED */ mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); } @@ -2447,6 +2456,8 @@ out: } return 0; error: + kfree(mos7840_port->led_dr); + usb_free_urb(mos7840_port->led_urb); kfree(mos7840_port->dr); kfree(mos7840_port->ctrl_buf); usb_free_urb(mos7840_port->control_urb); @@ -2467,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port) del_timer_sync(&mos7840_port->led_timer1); del_timer_sync(&mos7840_port->led_timer2); + + usb_kill_urb(mos7840_port->led_urb); + usb_free_urb(mos7840_port->led_urb); + kfree(mos7840_port->led_dr); } usb_kill_urb(mos7840_port->control_urb); usb_free_urb(mos7840_port->control_urb); -- cgit v0.10.2 From 555445cd11803c6bc93b2be31968f3949ef7708b Mon Sep 17 00:00:00 2001 From: Francesco Fusco Date: Wed, 24 Jul 2013 10:39:06 +0200 Subject: neigh: prevent overflowing params in /proc/sys/net/ipv4/neigh/ Without this patch, the fields app_solicit, gc_thresh1, gc_thresh2, gc_thresh3, proxy_qlen, ucast_solicit, mcast_solicit could have assumed negative values when setting large numbers. Signed-off-by: Francesco Fusco Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b7de821..9232c68 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2767,6 +2767,7 @@ EXPORT_SYMBOL(neigh_app_ns); #ifdef CONFIG_SYSCTL static int zero; +static int int_max = INT_MAX; static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN); static int proc_unres_qlen(struct ctl_table *ctl, int write, @@ -2819,19 +2820,25 @@ static struct neigh_sysctl_table { .procname = "mcast_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_UCAST_PROBE] = { .procname = "ucast_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_APP_PROBE] = { .procname = "app_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_RETRANS_TIME] = { .procname = "retrans_time", @@ -2874,7 +2881,9 @@ static struct neigh_sysctl_table { .procname = "proxy_qlen", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_ANYCAST_DELAY] = { .procname = "anycast_delay", @@ -2916,19 +2925,25 @@ static struct neigh_sysctl_table { .procname = "gc_thresh1", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_GC_THRESH2] = { .procname = "gc_thresh2", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, [NEIGH_VAR_GC_THRESH3] = { .procname = "gc_thresh3", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .extra1 = &zero, + .extra2 = &int_max, + .proc_handler = proc_dointvec_minmax, }, {}, }, -- cgit v0.10.2 From d738ce8fdc05ebf5b1475f8ae26d908c8c50970b Mon Sep 17 00:00:00 2001 From: Francesco Fusco Date: Wed, 24 Jul 2013 10:39:07 +0200 Subject: sysctl: range checking in do_proc_dointvec_ms_jiffies_conv When (integer) sysctl values are expressed in ms and have to be represented internally as jiffies. The msecs_to_jiffies function returns an unsigned long, which gets assigned to the integer. This patch prevents the value to be assigned if bigger than INT_MAX, done in a similar way as in cba9f3 ("Range checking in do_proc_dointvec_(userhz_)jiffies_conv"). Signed-off-by: Francesco Fusco CC: Andrew Morton CC: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ac09d98..07f6fc4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2346,7 +2346,11 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, int write, void *data) { if (write) { - *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); + unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); + + if (jif > INT_MAX) + return 1; + *valp = (int)jif; } else { int val = *valp; unsigned long lval; -- cgit v0.10.2 From d8af4dfd84329015e18ea3d83a84c46e92f21020 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 24 Jul 2013 17:25:08 +0800 Subject: net/tg3: Fix kernel crash While EEH error happens, we might not have network device instance (struct net_device) yet. So we can't access the instance safely and check its link state, which causes kernel crash. The patch fixes it. EEH: Frozen PE#2 on PHB#3 detected EEH: This PCI device has failed 1 times in the last hour EEH: Notify device drivers to shutdown (NULL net_device): PCI I/O error detected Unable to handle kernel paging request for data at address 0x00000048 Faulting instruction address: 0xd00000001c9387a8 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=1024 NUMA PowerNV : NIP [d00000001c9387a8] .tg3_io_error_detected+0x78/0x2a0 [tg3] LR [d00000001c9387a4] .tg3_io_error_detected+0x74/0x2a0 [tg3] Call Trace: [c000003f93a0f960] [d00000001c9387a4] .tg3_io_error_detected+0x74/0x2a0 [tg3] [c000003f93a0fa30] [c00000000003844c] .eeh_report_error+0xac/0x120 [c000003f93a0fac0] [c0000000000371bc] .eeh_pe_dev_traverse+0x8c/0x150 [c000003f93a0fb60] [c000000000038858] .eeh_handle_normal_event+0x128/0x3d0 [c000003f93a0fbf0] [c000000000038db8] .eeh_handle_event+0x2b8/0x2c0 [c000003f93a0fc90] [c000000000038e80] .eeh_event_handler+0xc0/0x170 [c000003f93a0fd30] [c0000000000cc000] .kthread+0xf0/0x100 [c000003f93a0fe30] [c00000000000a0dc] .ret_from_kernel_thread+0x5c/0x80 Reported-by: Wei Yang Signed-off-by: Gavin Shan Acked-by: Nithin Nayak Sujir Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index d964f30..aee1b9a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17773,7 +17773,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, rtnl_lock(); - if (!netif_running(netdev)) + /* We probably don't have netdev yet */ + if (!netdev || !netif_running(netdev)) goto done; tg3_phy_stop(tp); -- cgit v0.10.2 From c80dc13dda73db67e156b161d06c78f266b36ea6 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 24 Jul 2013 17:25:09 +0800 Subject: net/tg3: Fix warning from pci_disable_device() The patch fixes following warning. The PCI device might have been disabled somewhere else when we have EEH errors during early stage. Device tg3 disabling already-disabled device WARNING: at drivers/pci/pci.c:1403 : NIP [c00000000044fd5c] .pci_disable_device+0xcc/0xe0 LR [c00000000044fd58] .pci_disable_device+0xc8/0xe0 Call Trace: [c000003f80bc7370] [c00000000044fd58] .pci_disable_device+0xc8/0xe0 [c000003f80bc73f0] [d00000001cfe8fc0] .tg3_init_one+0x2f0/0x19f0 [tg3] [c000003f80bc74d0] [c0000000004534e8] .local_pci_probe+0x68/0xb0 [c000003f80bc7560] [c0000000004537c8] .pci_device_probe+0x198/0x1a0 [c000003f80bc7610] [c0000000004f9e98] .driver_probe_device+0xd8/0x450 [c000003f80bc76a0] [c0000000004fa3bc] .__driver_attach+0x10c/0x110 [c000003f80bc7730] [c0000000004f6e94] .bus_for_each_dev+0x94/0x100 [c000003f80bc77d0] [c0000000004f9634] .driver_attach+0x34/0x50 [c000003f80bc7850] [c0000000004f8f98] .bus_add_driver+0x288/0x380 [c000003f80bc78f0] [c0000000004fae2c] .driver_register+0x9c/0x200 [c000003f80bc7980] [c000000000453214] .__pci_register_driver+0x64/0x90 [c000003f80bc7a10] [d00000001cff7a60] .tg3_driver_init+0x2c/0x40 [tg3] [c000003f80bc7a80] [c00000000000b424] .do_one_initcall+0x144/0x1f0 [c000003f80bc7b70] [c0000000001244a0] .load_module+0x1f30/0x2700 [c000003f80bc7d40] [c000000000124e80] .SyS_finit_module+0xc0/0x110 [c000003f80bc7e30] [c000000000009dd4] syscall_exit+0x0/0x98 Reported-by: Wei Yang Signed-off-by: Gavin Shan Acked-by: Nithin Nayak Sujir Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index aee1b9a..ddebc7a 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17625,7 +17625,8 @@ err_out_free_res: pci_release_regions(pdev); err_out_disable_pdev: - pci_disable_device(pdev); + if (pci_is_enabled(pdev)) + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err; } -- cgit v0.10.2 From 4ffd9e2c4deda2ad90ce261174b2bc90e0660703 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 26 Jul 2013 15:29:40 -0700 Subject: ARC: SMP build breakage Signed-off-by: Vineet Gupta diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h index 8943c02..df57611 100644 --- a/arch/arc/include/asm/entry.h +++ b/arch/arc/include/asm/entry.h @@ -38,6 +38,7 @@ #include #include /* For VMALLOC_START */ #include /* For THREAD_SIZE */ +#include /* Note on the LD/ST addr modes with addr reg wback * -- cgit v0.10.2 From ebe7fdbaf3e90ea22feade6c9f5e50f42b23b6d8 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 26 Jul 2013 12:47:14 -0400 Subject: atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring atl1c uses netdev_alloc_skb to refill its rx dma ring, but that call makes no guarantees about the suitability of the memory for use in DMA. As a result we've gotten reports of atl1c drivers occasionally hanging and needing to be reset: https://bugzilla.kernel.org/show_bug.cgi?id=54021 Fix this by modifying the call to use the internal version __netdev_alloc_skb, where you can set the gfp_mask explicitly to include GFP_DMA. Tested by two reporters in the above bug, who have the hardware to validate it. Both report immediate cessation of the problem with this patch Signed-off-by: Neil Horman CC: Jay Cliburn CC: "David S. Miller" CC: stable@vger.kernel.org Tested-by: Luis Henriques Tested-by: Vincent Alquier Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 786a874..d5e38d1 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1660,7 +1660,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); + skb = __netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len, GFP_ATOMIC|GFP_DMA); if (unlikely(!skb)) { if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, "alloc rx buffer failed\n"); -- cgit v0.10.2 From d970d7fe65adff5efe75b4a73c4ffc9be57089f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 4 Jul 2013 11:28:51 +0200 Subject: serial/mxs-auart: fix race condition in interrupt handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handler needs to ack the pending events before actually handling them. Otherwise a new event might come in after it it considered non-pending or handled and is acked then without being handled. So this event is only noticed when the next interrupt happens. Without this patch an i.MX28 based machine running an rt-patched kernel regularly hangs during boot. Cc: stable@vger.kernel.org # v2.6.39+ Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 4f5f161..3de0fb2 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u, static irqreturn_t mxs_auart_irq_handle(int irq, void *context) { - u32 istatus, istat; + u32 istat; struct mxs_auart_port *s = context; u32 stat = readl(s->port.membase + AUART_STAT); - istatus = istat = readl(s->port.membase + AUART_INTR); + istat = readl(s->port.membase + AUART_INTR); + + /* ack irq */ + writel(istat & (AUART_INTR_RTIS + | AUART_INTR_TXIS + | AUART_INTR_RXIS + | AUART_INTR_CTSMIS), + s->port.membase + AUART_INTR_CLR); if (istat & AUART_INTR_CTSMIS) { uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); @@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) istat &= ~AUART_INTR_TXIS; } - writel(istatus & (AUART_INTR_RTIS - | AUART_INTR_TXIS - | AUART_INTR_RXIS - | AUART_INTR_CTSMIS), - s->port.membase + AUART_INTR_CLR); - return IRQ_HANDLED; } -- cgit v0.10.2 From 079a036f4283e2b0e5c26080b8c5112bc0cc1831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 28 Jun 2013 11:49:41 +0200 Subject: serial/mxs-auart: increase time to wait for transmitter to become idle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this patch the driver waits ~1 ms for the UART to become idle. At 115200n8 this time is (theoretically) enough to transfer 11.5 characters (= 115200 bits/s / (10 Bits/char) * 1ms). As the mxs-auart has a fifo size of 16 characters the clock is gated too early. The problem is worse for lower baud rates. This only happens to really shut down the transmitter in the middle of a transfer if /dev/ttyAPPx isn't opened in userspace (e.g. by a getty) but was at least once (because the bootloader doesn't disable the transmitter). So increase the timeout to 20 ms which should be enough for 9600n8, too. Moreover skip gating the clock if the timeout is elapsed. Cc: stable@vger.kernel.org # v2.6.39+ Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 3de0fb2..f85b8e6 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -851,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count) struct mxs_auart_port *s; struct uart_port *port; unsigned int old_ctrl0, old_ctrl2; - unsigned int to = 1000; + unsigned int to = 20000; if (co->index >= MXS_AUART_PORTS || co->index < 0) return; @@ -872,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count) uart_console_write(port, str, count, mxs_auart_console_putchar); - /* - * Finally, wait for transmitter to become empty - * and restore the TCR - */ + /* Finally, wait for transmitter to become empty ... */ while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) { + udelay(1); if (!to--) break; - udelay(1); } - writel(old_ctrl0, port->membase + AUART_CTRL0); - writel(old_ctrl2, port->membase + AUART_CTRL2); + /* + * ... and restore the TCR if we waited long enough for the transmitter + * to be idle. This might keep the transmitter enabled although it is + * unused, but that is better than to disable it while it is still + * transmitting. + */ + if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) { + writel(old_ctrl0, port->membase + AUART_CTRL0); + writel(old_ctrl2, port->membase + AUART_CTRL2); + } clk_disable(s->clk); } -- cgit v0.10.2 From 1d9e689c934bd5ecb0f273c6c65e0655c5cfee5f Mon Sep 17 00:00:00 2001 From: Gianluca Anzolin Date: Thu, 25 Jul 2013 07:26:16 +0200 Subject: tty_port: Fix refcounting leak in tty_port_tty_hangup() The function tty_port_tty_hangup() could leak a reference to the tty_struct: struct tty_struct *tty = tty_port_tty_get(port); if (tty && (!check_clocal || !C_CLOCAL(tty))) { tty_hangup(tty); tty_kref_put(tty); } If tty != NULL and the second condition is false we never call tty_kref_put and the reference is leaked. Fix by always calling tty_kref_put() which accepts a NULL argument. The patch fixes a regression introduced by commit aa27a094. Acked-by: Gustavo Padovan Signed-off-by: Gianluca Anzolin Acked-by: Jiri Slaby Cc: stable # 3.10 Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 121aeb9..f597e88 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) { struct tty_struct *tty = tty_port_tty_get(port); - if (tty && (!check_clocal || !C_CLOCAL(tty))) { + if (tty && (!check_clocal || !C_CLOCAL(tty))) tty_hangup(tty); - tty_kref_put(tty); - } + tty_kref_put(tty); } EXPORT_SYMBOL_GPL(tty_port_tty_hangup); -- cgit v0.10.2 From d5a12ea7a9e58d9e5c19d25cb668aadb396423ec Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 21 Jul 2013 10:14:15 +0800 Subject: serial: arc_uart: Fix module alias Platform drivers use "platform:" prefix in module alias. Also use DRIVER_NAME in MODULE_ALIAS to make module autoloading work. Signed-off-by: Axel Lin Acked-by: Vineet Gupta Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index cbf1d15..22f280a 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -773,6 +773,6 @@ module_init(arc_serial_init); module_exit(arc_serial_exit); MODULE_LICENSE("GPL"); -MODULE_ALIAS("plat-arcfpga/uart"); +MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("Vineet Gupta"); MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver"); -- cgit v0.10.2 From 6eddacae385052c7a1f4f60ffdf0eeec88088ad0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 27 Jul 2013 00:45:45 +0100 Subject: ARM: Fix sorting of machine- initializers So, there's a comment I put at the top of this, which people seem to fail to read. So let's fix it for them instead. Signed-off-by: Russell King diff --git a/arch/arm/Makefile b/arch/arm/Makefile index c0ac0f5..6fd2cea 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -153,6 +153,7 @@ machine-$(CONFIG_ARCH_DAVINCI) += davinci machine-$(CONFIG_ARCH_DOVE) += dove machine-$(CONFIG_ARCH_EBSA110) += ebsa110 machine-$(CONFIG_ARCH_EP93XX) += ep93xx +machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_GEMINI) += gemini machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_INTEGRATOR) += integrator @@ -160,15 +161,16 @@ machine-$(CONFIG_ARCH_IOP13XX) += iop13xx machine-$(CONFIG_ARCH_IOP32X) += iop32x machine-$(CONFIG_ARCH_IOP33X) += iop33x machine-$(CONFIG_ARCH_IXP4XX) += ixp4xx +machine-$(CONFIG_ARCH_KEYSTONE) += keystone machine-$(CONFIG_ARCH_KIRKWOOD) += kirkwood machine-$(CONFIG_ARCH_KS8695) += ks8695 machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx machine-$(CONFIG_ARCH_MMP) += mmp machine-$(CONFIG_ARCH_MSM) += msm machine-$(CONFIG_ARCH_MV78XX0) += mv78xx0 +machine-$(CONFIG_ARCH_MVEBU) += mvebu machine-$(CONFIG_ARCH_MXC) += imx machine-$(CONFIG_ARCH_MXS) += mxs -machine-$(CONFIG_ARCH_MVEBU) += mvebu machine-$(CONFIG_ARCH_NETX) += netx machine-$(CONFIG_ARCH_NOMADIK) += nomadik machine-$(CONFIG_ARCH_NSPIRE) += nspire @@ -176,7 +178,6 @@ machine-$(CONFIG_ARCH_OMAP1) += omap1 machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2 machine-$(CONFIG_ARCH_ORION5X) += orion5x machine-$(CONFIG_ARCH_PICOXCELL) += picoxcell -machine-$(CONFIG_ARCH_SIRF) += prima2 machine-$(CONFIG_ARCH_PXA) += pxa machine-$(CONFIG_ARCH_REALVIEW) += realview machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip @@ -186,25 +187,24 @@ machine-$(CONFIG_ARCH_S3C64XX) += s3c64xx machine-$(CONFIG_ARCH_S5P64X0) += s5p64x0 machine-$(CONFIG_ARCH_S5PC100) += s5pc100 machine-$(CONFIG_ARCH_S5PV210) += s5pv210 -machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_SA1100) += sa1100 machine-$(CONFIG_ARCH_SHARK) += shark machine-$(CONFIG_ARCH_SHMOBILE) += shmobile +machine-$(CONFIG_ARCH_SIRF) += prima2 +machine-$(CONFIG_ARCH_SOCFPGA) += socfpga +machine-$(CONFIG_ARCH_STI) += sti +machine-$(CONFIG_ARCH_SUNXI) += sunxi machine-$(CONFIG_ARCH_TEGRA) += tegra machine-$(CONFIG_ARCH_U300) += u300 machine-$(CONFIG_ARCH_U8500) += ux500 machine-$(CONFIG_ARCH_VERSATILE) += versatile machine-$(CONFIG_ARCH_VEXPRESS) += vexpress +machine-$(CONFIG_ARCH_VIRT) += virt machine-$(CONFIG_ARCH_VT8500) += vt8500 machine-$(CONFIG_ARCH_W90X900) += w90x900 +machine-$(CONFIG_ARCH_ZYNQ) += zynq machine-$(CONFIG_FOOTBRIDGE) += footbridge -machine-$(CONFIG_ARCH_SOCFPGA) += socfpga machine-$(CONFIG_PLAT_SPEAR) += spear -machine-$(CONFIG_ARCH_STI) += sti -machine-$(CONFIG_ARCH_VIRT) += virt -machine-$(CONFIG_ARCH_ZYNQ) += zynq -machine-$(CONFIG_ARCH_SUNXI) += sunxi -machine-$(CONFIG_ARCH_KEYSTONE) += keystone # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. -- cgit v0.10.2 From 0699a73af3811b66b1ab5650575acee5eea841ab Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 22 Jul 2013 21:32:09 +0200 Subject: firewire: fix libdc1394/FlyCap2 iso event regression Commit 18d627113b83 (firewire: prevent dropping of completed iso packet header data) was intended to be an obvious bug fix, but libdc1394 and FlyCap2 depend on the old behaviour by ignoring all returned information and thus not noticing that not all packets have been received yet. The result was that the video frame buffers would be saved before they contained the correct data. Reintroduce the old behaviour for old clients. Tested-by: Stepan Salenikovich Tested-by: Josep Bosch Cc: # 3.4+ Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 7ef316f..ac1b43a 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -54,6 +54,7 @@ #define FW_CDEV_KERNEL_VERSION 5 #define FW_CDEV_VERSION_EVENT_REQUEST2 4 #define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 +#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5 struct client { u32 version; @@ -1005,6 +1006,8 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg) a->channel, a->speed, a->header_size, cb, client); if (IS_ERR(context)) return PTR_ERR(context); + if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW) + context->drop_overflow_headers = true; /* We only support one context at this time. */ spin_lock_irq(&client->lock); diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9e1db64..afb701e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2749,8 +2749,11 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr) { u32 *ctx_hdr; - if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) + if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) { + if (ctx->base.drop_overflow_headers) + return; flush_iso_completions(ctx); + } ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]); @@ -2910,8 +2913,11 @@ static int handle_it_packet(struct context *context, sync_it_packet_for_cpu(context, d); - if (ctx->header_length + 4 > PAGE_SIZE) + if (ctx->header_length + 4 > PAGE_SIZE) { + if (ctx->base.drop_overflow_headers) + return 1; flush_iso_completions(ctx); + } ctx_hdr = ctx->header + ctx->header_length; ctx->last_timestamp = le16_to_cpu(last->res_count); diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 3b0e820..5d7782e 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -436,6 +436,7 @@ struct fw_iso_context { int type; int channel; int speed; + bool drop_overflow_headers; size_t header_size; union { fw_iso_callback_t sc; diff --git a/include/uapi/linux/firewire-cdev.h b/include/uapi/linux/firewire-cdev.h index d500369..1db453e 100644 --- a/include/uapi/linux/firewire-cdev.h +++ b/include/uapi/linux/firewire-cdev.h @@ -215,8 +215,8 @@ struct fw_cdev_event_request2 { * with the %FW_CDEV_ISO_INTERRUPT bit set, when explicitly requested with * %FW_CDEV_IOC_FLUSH_ISO, or when there have been so many completed packets * without the interrupt bit set that the kernel's internal buffer for @header - * is about to overflow. (In the last case, kernels with ABI version < 5 drop - * header data up to the next interrupt packet.) + * is about to overflow. (In the last case, ABI versions < 5 drop header data + * up to the next interrupt packet.) * * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT): * -- cgit v0.10.2 From fafb6ebe384e62e68519ae8f5ae9b2cb578d7dde Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 27 Jul 2013 20:00:44 -0700 Subject: Revert "atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring" This reverts commit ebe7fdbaf3e90ea22feade6c9f5e50f42b23b6d8. This change is not correct. GFP_DMA is not necessary for this device. There is some other problem causing this bug. Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index d5e38d1..786a874 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1660,7 +1660,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = __netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len, GFP_ATOMIC|GFP_DMA); + skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); if (unlikely(!skb)) { if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, "alloc rx buffer failed\n"); -- cgit v0.10.2 From c70a31750679ca10a46dd0cc2d57ed7b54dbe7c2 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Fri, 26 Jul 2013 16:24:00 -0400 Subject: qlcnic: Fix initialization of work function. Work function needs to be initialized before we participate in inter device communication (IDC). Signed-off-by: Jitendra Kalsaria Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index f41dfab..51ab4b5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2123,6 +2123,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status); qlcnic_83xx_clear_function_resources(adapter); + INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); + /* register for NIC IDC AEN Events */ qlcnic_83xx_register_nic_idc_func(adapter, 1); @@ -2140,8 +2142,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) if (adapter->nic_ops->init_driver(adapter)) return -EIO; - INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - /* Periodically monitor device status */ qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work); -- cgit v0.10.2 From 6226204bcf20d2bb8e47e996c1688186355c1db4 Mon Sep 17 00:00:00 2001 From: Pratik Pujar Date: Fri, 26 Jul 2013 16:24:01 -0400 Subject: qlcnic: Fix operation type and command type. Operation type and command type is not set correct in back channel response. Signed-off-by: Pratik Pujar Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 62380ce..56e85f9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -762,6 +762,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type) memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); mbx->req.arg[0] = (type | (mbx->req.num << 16) | (3 << 29)); + mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16; return 0; } } @@ -813,6 +814,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans, cmd->req.num = trans->req_pay_size / 4; cmd->rsp.num = trans->rsp_pay_size / 4; hdr = trans->rsp_hdr; + cmd->op_type = trans->req_hdr->op_type; } trans->trans_id = seq; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 46aeb59..9bdd51e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -641,8 +641,6 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans, int err; adapter = vf->adapter; - cmd->rsp.arg[0] = trans->req_hdr->cmd_op; - cmd->rsp.arg[0] |= (1 << 16); if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) { err = qlcnic_sriov_pf_config_vport(adapter, 1, func); @@ -1187,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, u8 cmd_op, mode = vp->vlan_mode; cmd_op = trans->req_hdr->cmd_op; - cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25; + cmd->rsp.arg[0] |= 1 << 25; switch (mode) { case QLC_GUEST_VLAN_MODE: -- cgit v0.10.2 From 7cfc1cebdaee367c30e8944dd5adf2f6bbae8123 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Fri, 26 Jul 2013 16:24:02 -0400 Subject: qlcnic: Fix setting Guest VLAN o When configuring guest VLAN after PVID configuration, VF was loading with previously configured PVID. Clear the PVID which was previously configured before configuring guest VLAN. o Display guest VLAN when it is configured Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 9bdd51e..eb49cd6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -1749,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, switch (vlan) { case 4095: + vp->vlan = 0; vp->vlan_mode = QLC_GUEST_VLAN_MODE; break; case 0: @@ -1767,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, return 0; } +static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter, + struct qlcnic_vport *vp, int vf) +{ + __u32 vlan = 0; + + switch (vp->vlan_mode) { + case QLC_PVID_MODE: + vlan = vp->vlan; + break; + case QLC_GUEST_VLAN_MODE: + vlan = MAX_VLAN_ID; + break; + case QLC_NO_VLAN_MODE: + vlan = 0; + break; + default: + netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n", + vp->vlan_mode, vf); + } + + return vlan; +} + int qlcnic_sriov_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi) { @@ -1782,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev, vp = sriov->vf_info[vf].vp; memcpy(&ivi->mac, vp->mac, ETH_ALEN); - ivi->vlan = vp->vlan; + ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf); ivi->qos = vp->qos; ivi->spoofchk = vp->spoofchk; if (vp->max_tx_bw == MAX_BW) -- cgit v0.10.2 From c2534384233647a8702eca291199b94ffedc12d3 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Fri, 26 Jul 2013 16:24:03 -0400 Subject: qlcnic: Fix diagnostic interrupt test for 83xx adapters. o Initialize proper interrupt handler for 83xx. Signed-off-by: Manish Chopra Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 41635f2..cc78d39 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -1383,6 +1383,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter) if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) { if (qlcnic_82xx_check(adapter)) handler = qlcnic_tmp_intr; + else + handler = qlcnic_83xx_tmp_intr; if (!QLCNIC_IS_MSI_FAMILY(adapter)) flags |= IRQF_SHARED; -- cgit v0.10.2 From 031916568a1aa2ef1809f86d26f0bcfa215ff5c0 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 25 Jul 2013 14:05:53 +0800 Subject: net: fec: workaround stop tx during errata ERR006358 If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously detected as not set during a prior frame transmission, then the ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in frames not being transmitted until there is a 0-to-1 transition on ENET_TDAR[TDAR]. Workarounds: code can use the transmit frame interrupt flag (ENET_EIR[TXF]) as a method to detect whether the ENET has completed transmission and the ENET_TDAR[TDAR] has been cleared. If ENET_TDAR[TDAR] is detected as cleared when packets are queued and waiting for transmit, then a write to the TDAR bit will restart TxBD processing. This case main happen when loading is light. A ethernet package may not send out utile next package put into tx queue. How to test: while [ true ] do ping -s 10000 -w 4 ping -s 6000 -w 2 ping -s 4000 -w 2 ping -s 10000 -w 2 done You will see below result in overnight test. 6008 bytes from 10.192.242.116: seq=1 ttl=128 time=0.722 ms 4008 bytes from 10.192.242.116: seq=0 ttl=128 time=1001.008 ms 4008 bytes from 10.192.242.116: seq=1 ttl=128 time=1.010 ms 10008 bytes from 10.192.242.116: seq=0 ttl=128 time=0.896 ms After apply this patch, >1000ms delay disappear. Signed-off-by: Frank Li Acked-by: Fugang Duan Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 2b0a0ea..ae23600 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -259,6 +259,7 @@ struct bufdesc_ex { struct fec_enet_delayed_work { struct delayed_work delay_work; bool timeout; + bool trig_tx; }; /* The FEC buffer descriptors track the ring buffers. The rx_bd_base and diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f0f0e96..0dda454 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev); #define FEC_QUIRK_HAS_CSUM (1 << 5) /* Controller has hardware vlan support */ #define FEC_QUIRK_HAS_VLAN (1 << 6) +/* ENET IP errata ERR006358 + * + * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously + * detected as not set during a prior frame transmission, then the + * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs + * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in + * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously + * detected as not set during a prior frame transmission, then the + * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs + * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in + * frames not being transmitted until there is a 0-to-1 transition on + * ENET_TDAR[TDAR]. + */ +#define FEC_QUIRK_ERR006358 (1 << 7) static struct platform_device_id fec_devtype[] = { { @@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = { .name = "imx6q-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | - FEC_QUIRK_HAS_VLAN, + FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358, }, { .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC, @@ -275,7 +289,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); - struct bufdesc *bdp; + struct bufdesc *bdp, *bdp_pre; void *bufaddr; unsigned short status; unsigned int index; @@ -370,6 +384,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) ebdp->cbd_esc |= BD_ENET_TX_PINS; } } + + bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex); + if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && + !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { + fep->delay_work.trig_tx = true; + schedule_delayed_work(&(fep->delay_work.delay_work), + msecs_to_jiffies(1)); + } + /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; @@ -689,6 +712,11 @@ static void fec_enet_work(struct work_struct *work) fec_restart(fep->netdev, fep->full_duplex); netif_wake_queue(fep->netdev); } + + if (fep->delay_work.trig_tx) { + fep->delay_work.trig_tx = false; + writel(0, fep->hwp + FEC_X_DES_ACTIVE); + } } static void -- cgit v0.10.2 From c74f2b2678f40b80265dd53556f1f778c8e1823f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 26 Jul 2013 11:00:10 +0200 Subject: genetlink: release cb_lock before requesting additional module Requesting external module with cb_lock taken can result in the deadlock like showed below: [ 2458.111347] Showing all locks held in the system: [ 2458.111347] 1 lock held by NetworkManager/582: [ 2458.111347] #0: (cb_lock){++++++}, at: [] genl_rcv+0x19/0x40 [ 2458.111347] 1 lock held by modprobe/603: [ 2458.111347] #0: (cb_lock){++++++}, at: [] genl_lock_all+0x15/0x30 [ 2461.579457] SysRq : Show Blocked State [ 2461.580103] task PC stack pid father [ 2461.580103] NetworkManager D ffff880034b84500 4040 582 1 0x00000080 [ 2461.580103] ffff8800197ff720 0000000000000046 00000000001d5340 ffff8800197fffd8 [ 2461.580103] ffff8800197fffd8 00000000001d5340 ffff880019631700 7fffffffffffffff [ 2461.580103] ffff8800197ff880 ffff8800197ff878 ffff880019631700 ffff880019631700 [ 2461.580103] Call Trace: [ 2461.580103] [] schedule+0x29/0x70 [ 2461.580103] [] schedule_timeout+0x1c1/0x360 [ 2461.580103] [] ? mark_held_locks+0xbb/0x140 [ 2461.580103] [] ? _raw_spin_unlock_irq+0x2c/0x50 [ 2461.580103] [] ? trace_hardirqs_on_caller+0xfd/0x1c0 [ 2461.580103] [] wait_for_completion_killable+0xe8/0x170 [ 2461.580103] [] ? wake_up_state+0x20/0x20 [ 2461.580103] [] call_usermodehelper_exec+0x1a5/0x210 [ 2461.580103] [] ? wait_for_completion_killable+0x3d/0x170 [ 2461.580103] [] __request_module+0x1b3/0x370 [ 2461.580103] [] ? trace_hardirqs_on_caller+0xfd/0x1c0 [ 2461.580103] [] ctrl_getfamily+0x159/0x190 [ 2461.580103] [] genl_family_rcv_msg+0x1f4/0x2e0 [ 2461.580103] [] ? genl_family_rcv_msg+0x2e0/0x2e0 [ 2461.580103] [] genl_rcv_msg+0x8e/0xd0 [ 2461.580103] [] netlink_rcv_skb+0xa9/0xc0 [ 2461.580103] [] genl_rcv+0x28/0x40 [ 2461.580103] [] netlink_unicast+0xdd/0x190 [ 2461.580103] [] netlink_sendmsg+0x329/0x750 [ 2461.580103] [] sock_sendmsg+0x99/0xd0 [ 2461.580103] [] ? local_clock+0x5f/0x70 [ 2461.580103] [] ? lock_release_non_nested+0x308/0x350 [ 2461.580103] [] ___sys_sendmsg+0x39e/0x3b0 [ 2461.580103] [] ? kvm_clock_read+0x2f/0x50 [ 2461.580103] [] ? sched_clock+0x9/0x10 [ 2461.580103] [] ? sched_clock_local+0x1d/0x80 [ 2461.580103] [] ? sched_clock_cpu+0xa8/0x100 [ 2461.580103] [] ? trace_hardirqs_off+0xd/0x10 [ 2461.580103] [] ? local_clock+0x5f/0x70 [ 2461.580103] [] ? lock_release_holdtime.part.28+0xf/0x1a0 [ 2461.580103] [] ? fget_light+0xf9/0x510 [ 2461.580103] [] ? fget_light+0x3c/0x510 [ 2461.580103] [] __sys_sendmsg+0x42/0x80 [ 2461.580103] [] SyS_sendmsg+0x12/0x20 [ 2461.580103] [] system_call_fastpath+0x16/0x1b [ 2461.580103] modprobe D ffff88000f2c8000 4632 603 602 0x00000080 [ 2461.580103] ffff88000f04fba8 0000000000000046 00000000001d5340 ffff88000f04ffd8 [ 2461.580103] ffff88000f04ffd8 00000000001d5340 ffff8800377d4500 ffff8800377d4500 [ 2461.580103] ffffffff81d0b260 ffffffff81d0b268 ffffffff00000000 ffffffff81d0b2b0 [ 2461.580103] Call Trace: [ 2461.580103] [] schedule+0x29/0x70 [ 2461.580103] [] rwsem_down_write_failed+0xed/0x1a0 [ 2461.580103] [] ? update_cpu_load_active+0x10/0xb0 [ 2461.580103] [] call_rwsem_down_write_failed+0x13/0x20 [ 2461.580103] [] ? down_write+0x9d/0xb2 [ 2461.580103] [] ? genl_lock_all+0x15/0x30 [ 2461.580103] [] genl_lock_all+0x15/0x30 [ 2461.580103] [] genl_register_family+0x53/0x1f0 [ 2461.580103] [] ? 0xffffffffa01dbfff [ 2461.580103] [] genl_register_family_with_ops+0x20/0x80 [ 2461.580103] [] ? 0xffffffffa01dbfff [ 2461.580103] [] nl80211_init+0x24/0xf0 [cfg80211] [ 2461.580103] [] ? 0xffffffffa01dbfff [ 2461.580103] [] cfg80211_init+0x43/0xdb [cfg80211] [ 2461.580103] [] do_one_initcall+0xfa/0x1b0 [ 2461.580103] [] ? set_memory_nx+0x43/0x50 [ 2461.580103] [] load_module+0x1c6f/0x27f0 [ 2461.580103] [] ? store_uevent+0x40/0x40 [ 2461.580103] [] SyS_finit_module+0x86/0xb0 [ 2461.580103] [] system_call_fastpath+0x16/0x1b [ 2461.580103] Sched Debug Version: v0.10, 3.11.0-0.rc1.git4.1.fc20.x86_64 #1 Problem start to happen after adding net-pf-16-proto-16-family-nl80211 alias name to cfg80211 module by below commit (though that commit itself is perfectly fine): commit fb4e156886ce6e8309e912d8b370d192330d19d3 Author: Marcel Holtmann Date: Sun Apr 28 16:22:06 2013 -0700 nl80211: Add generic netlink module alias for cfg80211/nl80211 Reported-and-tested-by: Jeff Layton Reported-by: Richard W.M. Jones Signed-off-by: Stanislaw Gruszka Reviewed-by: Pravin B Shelar Signed-off-by: David S. Miller diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 2fd6dbe..1076fe1 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -877,8 +877,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) #ifdef CONFIG_MODULES if (res == NULL) { genl_unlock(); + up_read(&cb_lock); request_module("net-pf-%d-proto-%d-family-%s", PF_NETLINK, NETLINK_GENERIC, name); + down_read(&cb_lock); genl_lock(); res = genl_family_find_byname(name); } -- cgit v0.10.2 From fc51446021f42aca8906e701fc2292965aafcb15 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 23 Jul 2013 10:24:50 +0200 Subject: dma: pl330: Fix cyclic transfers Allocate a descriptor for each period of a cyclic transfer, not just the first. Also since the callback needs to be called for each finished period make sure to initialize the callback and callback_param fields of each descriptor in a cyclic transfer. Cc: stable@vger.kernel.org Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 593827b..fa645d8 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2505,6 +2505,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx) /* Assign cookies to all nodes */ while (!list_empty(&last->node)) { desc = list_entry(last->node.next, struct dma_pl330_desc, node); + if (pch->cyclic) { + desc->txd.callback = last->txd.callback; + desc->txd.callback_param = last->txd.callback_param; + } dma_cookie_assign(&desc->txd); @@ -2688,45 +2692,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( size_t period_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { - struct dma_pl330_desc *desc; + struct dma_pl330_desc *desc = NULL, *first = NULL; struct dma_pl330_chan *pch = to_pchan(chan); + struct dma_pl330_dmac *pdmac = pch->dmac; + unsigned int i; dma_addr_t dst; dma_addr_t src; - desc = pl330_get_desc(pch); - if (!desc) { - dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", - __func__, __LINE__); + if (len % period_len != 0) return NULL; - } - switch (direction) { - case DMA_MEM_TO_DEV: - desc->rqcfg.src_inc = 1; - desc->rqcfg.dst_inc = 0; - desc->req.rqtype = MEMTODEV; - src = dma_addr; - dst = pch->fifo_addr; - break; - case DMA_DEV_TO_MEM: - desc->rqcfg.src_inc = 0; - desc->rqcfg.dst_inc = 1; - desc->req.rqtype = DEVTOMEM; - src = pch->fifo_addr; - dst = dma_addr; - break; - default: + if (!is_slave_direction(direction)) { dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n", __func__, __LINE__); return NULL; } - desc->rqcfg.brst_size = pch->burst_sz; - desc->rqcfg.brst_len = 1; + for (i = 0; i < len / period_len; i++) { + desc = pl330_get_desc(pch); + if (!desc) { + dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + __func__, __LINE__); - pch->cyclic = true; + if (!first) + return NULL; + + spin_lock_irqsave(&pdmac->pool_lock, flags); + + while (!list_empty(&first->node)) { + desc = list_entry(first->node.next, + struct dma_pl330_desc, node); + list_move_tail(&desc->node, &pdmac->desc_pool); + } + + list_move_tail(&first->node, &pdmac->desc_pool); - fill_px(&desc->px, dst, src, period_len); + spin_unlock_irqrestore(&pdmac->pool_lock, flags); + + return NULL; + } + + switch (direction) { + case DMA_MEM_TO_DEV: + desc->rqcfg.src_inc = 1; + desc->rqcfg.dst_inc = 0; + desc->req.rqtype = MEMTODEV; + src = dma_addr; + dst = pch->fifo_addr; + break; + case DMA_DEV_TO_MEM: + desc->rqcfg.src_inc = 0; + desc->rqcfg.dst_inc = 1; + desc->req.rqtype = DEVTOMEM; + src = pch->fifo_addr; + dst = dma_addr; + break; + default: + break; + } + + desc->rqcfg.brst_size = pch->burst_sz; + desc->rqcfg.brst_len = 1; + fill_px(&desc->px, dst, src, period_len); + + if (!first) + first = desc; + else + list_add_tail(&desc->node, &first->node); + + dma_addr += period_len; + } + + if (!desc) + return NULL; + + pch->cyclic = true; + desc->txd.flags = flags; return &desc->txd; } -- cgit v0.10.2 From 683a0e4d7971c3186dc4d429027debfe309129aa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sat, 27 Jul 2013 13:34:42 +0200 Subject: USB: mos7840: fix pointer casts Silence compiler warnings on 64-bit systems introduced by commit 05cf0dec ("USB: mos7840: fix race in led handling") which uses the usb-serial data pointer to temporarily store the device type during probe but failed to add the required casts. [gregkh - change uintptr_t to unsigned long] Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c10fc15..d953d67 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2221,14 +2221,14 @@ static int mos7840_probe(struct usb_serial *serial, kfree(buf); out: - usb_set_serial_data(serial, (void *)device_type); + usb_set_serial_data(serial, (void *)(unsigned long)device_type); return 0; } static int mos7840_calc_num_ports(struct usb_serial *serial) { - int device_type = (int)usb_get_serial_data(serial); + int device_type = (unsigned long)usb_get_serial_data(serial); int mos7840_num_ports; mos7840_num_ports = (device_type >> 4) & 0x000F; @@ -2239,7 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - int device_type = (int)usb_get_serial_data(serial); + int device_type = (unsigned long)usb_get_serial_data(serial); struct moschip_port *mos7840_port; int status; int pnum; -- cgit v0.10.2 From 1eb9ac14c34a948bf1538bfb9034e8ab29099a64 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 26 Jul 2013 05:46:35 -0700 Subject: ixgbe: Fix Tx Hang issue with lldpad on 82598EB This patch fixes an issue with the 82598EB device, where lldpad is causing Tx Hangs on the card as soon as it attempts to configure DCB for the device. The adapter will continually Tx hang and reset in a loop. Signed-off-by: Jacob Keller Cc: Stable Tested-by: Phil Schmitt Tested-by: Jack Morgan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c index ac78077..7a77f37 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c @@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, /* Enable arbiter */ reg &= ~IXGBE_DPMCS_ARBDIS; - /* Enable DFP and Recycle mode */ - reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); reg |= IXGBE_DPMCS_TSOEF; + /* Configure Max TSO packet size 34KB including payload and headers */ reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); -- cgit v0.10.2 From 7e44892c1b6bb499cb2f6d5c0f4afcc077a26074 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Fri, 26 Jul 2013 05:46:36 -0700 Subject: igb: fix vlan filtering in promisc mode when not in VT mode This patch fixes a VT mode check to make sure VLAN filters are disabled when in promisc mode and VT is not enabled. The problem with the previous check was that: E1000_MRQC_ENABLE_VMDQ is defined as 0x00000003 but when not in VT mode: mrqc |= E1000_MRQC_ENABLE_RSS_4Q (0x00000002) So the above check will trigger regardless if VT mode is being used or not. Signed-off-by: Emil Tantilov Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 6a0c1b6..c1d72c0 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev) rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE); if (netdev->flags & IFF_PROMISC) { - u32 mrqc = rd32(E1000_MRQC); /* retain VLAN HW filtering if in VT mode */ - if (mrqc & E1000_MRQC_ENABLE_VMDQ) + if (adapter->vfs_allocated_count) rctl |= E1000_RCTL_VFE; rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME); -- cgit v0.10.2 From 8b00e1831cea899cd4dfe04e574c26e376c27368 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 2 Jul 2013 09:28:21 +0300 Subject: fbdev/atyfb: fix recent breakage in correct_chipset() The 6e36308a6f "fb: fix atyfb build warning" isn't right. It makes all the indexes off by one. This patch reverts it and casts the ARRAY_SIZE() to int to silence the build warning. Signed-off-by: Dan Carpenter Acked-by: Randy Dunlap Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index a89c15d..9b0f12c 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par) const char *name; int i; - for (i = ARRAY_SIZE(aty_chips); i > 0; i--) - if (par->pci_id == aty_chips[i - 1].pci_id) + for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--) + if (par->pci_id == aty_chips[i].pci_id) break; if (i < 0) -- cgit v0.10.2 From 7808e3291e1e101e9ad6e8263119c4a2abae05ef Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 12 Jul 2013 21:20:03 +0800 Subject: video: sh7760fb: fix to pass correct device identity to free_irq() free_irq() expects the same device identity that was passed to corresponding request_irq(), otherwise the IRQ is not freed. Signed-off-by: Wei Yongjun Signed-off-by: Tomi Valkeinen diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index a8c6c43..1265b25 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev) fb_dealloc_cmap(&info->cmap); sh7760fb_free_mem(info); if (par->irq >= 0) - free_irq(par->irq, par); + free_irq(par->irq, &par->vsync); iounmap(par->base); release_mem_region(par->ioarea->start, resource_size(par->ioarea)); framebuffer_release(info); -- cgit v0.10.2 From 3f8e2d75c14660abc8b69206f30190ab93304379 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 24 Jul 2013 02:32:46 +0300 Subject: Bluetooth: Fix HCI init for BlueFRITZ! devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit None of the BlueFRITZ! devices with manufacurer ID 31 (AVM Berlin) support HCI_Read_Local_Supported_Commands. It is safe to use the manufacturer ID (instead of e.g. a USB ID specific quirk) because the company never created any newer controllers. < HCI Command: Read Local Supported Comm.. (0x04|0x0002) plen 0 [hci0] 0.210014 > HCI Event: Command Status (0x0f) plen 4 [hci0] 0.217361 Read Local Supported Commands (0x04|0x0002) ncmd 1 Status: Unknown HCI Command (0x01) Reported-by: Jörg Esser Signed-off-by: Johan Hedberg Tested-by: Jörg Esser Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 64d33d1..0176f20 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -513,7 +513,10 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt) hci_setup_event_mask(req); - if (hdev->hci_ver > BLUETOOTH_VER_1_1) + /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read + * local supported commands HCI command. + */ + if (hdev->manufacturer != 31 && hdev->hci_ver > BLUETOOTH_VER_1_1) hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); if (lmp_ssp_capable(hdev)) { -- cgit v0.10.2 From 8abc6fa163d40bccc80c7b1f821f2579ab26864d Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 26 Jul 2013 14:37:13 +0200 Subject: usb: gadget: multi: fix error return code in cdc_do_config() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Introduced by commit 59835a (usb: gadget: multi: use function framework for ACM.) Make rndis_do_config() consistent with cdc_do_config() in the way it handles returning the PTR_ERR(f_acm_*). Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 032b96a..2a1ebef 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c) return ret; f_acm_rndis = usb_get_function(fi_acm); - if (IS_ERR(f_acm_rndis)) { - ret = PTR_ERR(f_acm_rndis); - goto err_func_acm; - } + if (IS_ERR(f_acm_rndis)) + return PTR_ERR(f_acm_rndis); ret = usb_add_function(c, f_acm_rndis); if (ret) @@ -178,7 +176,6 @@ err_fsg: usb_remove_function(c, f_acm_rndis); err_conf: usb_put_function(f_acm_rndis); -err_func_acm: return ret; } @@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c) /* implicit port_num is zero */ f_acm_multi = usb_get_function(fi_acm); if (IS_ERR(f_acm_multi)) - goto err_func_acm; + return PTR_ERR(f_acm_multi); ret = usb_add_function(c, f_acm_multi); if (ret) @@ -241,7 +238,6 @@ err_fsg: usb_remove_function(c, f_acm_multi); err_conf: usb_put_function(f_acm_multi); -err_func_acm: return ret; } -- cgit v0.10.2 From 96edc98e7894a7ac5a1cb3c6059455304a6cde6a Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 26 Jul 2013 14:37:14 +0200 Subject: usb: gadget: f_phonet: remove unused preprocessor conditional The compatibility layer which the USBF_PHONET_INCLUDED was a part of is no longer present - the USBF_PHONET_INCLUDED is not #defined by anyone anymore, so the ifndef is always true. Removing it. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 1bf26e9..eb3aa81 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; int status, i; -#ifndef USBF_PHONET_INCLUDED struct f_phonet_opts *phonet_opts; phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst); @@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f) return status; phonet_opts->bound = true; } -#endif /* Reserve interface IDs */ status = usb_interface_id(c, f); -- cgit v0.10.2 From 1894870eb4240399fabc6f0cb8c6fff4e6edbe83 Mon Sep 17 00:00:00 2001 From: Rong Wang Date: Sun, 28 Jul 2013 23:01:35 +0800 Subject: usb: gadget: udc-core: fix the typo of udc state attribute The name of udc state attribute file under sysfs is registered as "state", while usb_gadget_set_state take it as "status" when it's going to update. This patch fixes the typo. Signed-off-by: Rong Wang Signed-off-by: Barry Song Cc: Signed-off-by: Felipe Balbi diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index c28ac98..13e25f8 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -109,7 +109,7 @@ void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state) { gadget->state = state; - sysfs_notify(&gadget->dev.kobj, NULL, "status"); + sysfs_notify(&gadget->dev.kobj, NULL, "state"); } EXPORT_SYMBOL_GPL(usb_gadget_set_state); -- cgit v0.10.2 From 53e21fbc288218a423959f878c86471a0e323a9a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 27 Jul 2013 14:11:14 -0500 Subject: Bluetooth: Fix calling request callback more than once In certain circumstances, such as an HCI driver using __hci_cmd_sync_ev with HCI_EV_CMD_COMPLETE as the expected completion event there is the chance that hci_event_packet will call hci_req_cmd_complete twice (once for the explicitly looked after event and another time in the actual handler of cmd_complete). In the case of __hci_cmd_sync_ev this introduces a race where the first call wakes up the blocking __hci_cmd_sync_ev and lets it complete. However, by the time that a second __hci_cmd_sync_ev call is already in progress the second hci_req_cmd_complete call (from the previous operation) will wake up the blocking function prematurely and cause it to fail, as witnessed by the following log: [ 639.232195] hci_rx_work: hci0 Event packet [ 639.232201] hci_req_cmd_complete: opcode 0xfc8e status 0x00 [ 639.232205] hci_sent_cmd_data: hci0 opcode 0xfc8e [ 639.232210] hci_req_sync_complete: hci0 result 0x00 [ 639.232220] hci_cmd_complete_evt: hci0 opcode 0xfc8e [ 639.232225] hci_req_cmd_complete: opcode 0xfc8e status 0x00 [ 639.232228] __hci_cmd_sync_ev: hci0 end: err 0 [ 639.232234] __hci_cmd_sync_ev: hci0 [ 639.232238] hci_req_add_ev: hci0 opcode 0xfc8e plen 250 [ 639.232242] hci_prepare_cmd: skb len 253 [ 639.232246] hci_req_run: length 1 [ 639.232250] hci_sent_cmd_data: hci0 opcode 0xfc8e [ 639.232255] hci_req_sync_complete: hci0 result 0x00 [ 639.232266] hci_cmd_work: hci0 cmd_cnt 1 cmd queued 1 [ 639.232271] __hci_cmd_sync_ev: hci0 end: err 0 [ 639.232276] Bluetooth: hci0 sending Intel patch command (0xfc8e) failed (-61) Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0176f20..48e1e04 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3442,8 +3442,16 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) */ if (hdev->sent_cmd) { req_complete = bt_cb(hdev->sent_cmd)->req.complete; - if (req_complete) + + if (req_complete) { + /* We must set the complete callback to NULL to + * avoid calling the callback more than once if + * this function gets called again. + */ + bt_cb(hdev->sent_cmd)->req.complete = NULL; + goto call_complete; + } } /* Remove all pending commands belonging to this request */ -- cgit v0.10.2 From 228b30234f258a193317874854eee1ca7807186e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 27 Jul 2013 01:13:26 +0200 Subject: Revert "cpuidle: Quickly notice prediction failure in general case" Revert commit e11538d1 (cpuidle: Quickly notice prediction failure in general case), since it depends on commit 69a37be (cpuidle: Quickly notice prediction failure for repeat mode) that has been identified as the source of a significant performance regression in v3.8 and later. Requested-by: Jeremy Eder Tested-by: Len Brown Cc: 3.8+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index fe343a0..b69a87e 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -34,7 +34,7 @@ static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer); static DEFINE_PER_CPU(int, hrtimer_status); /* menu hrtimer mode */ -enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL}; +enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT}; /* * Concepts and ideas behind the menu governor @@ -116,13 +116,6 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL}; * */ -/* - * The C-state residency is so long that is is worthwhile to exit - * from the shallow C-state and re-enter into a deeper C-state. - */ -static unsigned int perfect_cstate_ms __read_mostly = 30; -module_param(perfect_cstate_ms, uint, 0000); - struct menu_device { int last_state_idx; int needs_update; @@ -223,16 +216,6 @@ EXPORT_SYMBOL_GPL(menu_hrtimer_cancel); static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) { int cpu = smp_processor_id(); - struct menu_device *data = &per_cpu(menu_devices, cpu); - - /* In general case, the expected residency is much larger than - * deepest C-state target residency, but prediction logic still - * predicts a small predicted residency, so the prediction - * history is totally broken if the timer is triggered. - * So reset the correction factor. - */ - if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL) - data->correction_factor[data->bucket] = RESOLUTION * DECAY; per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; @@ -389,7 +372,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) /* not deepest C-state chosen for low predicted residency */ if (low_predicted) { unsigned int timer_us = 0; - unsigned int perfect_us = 0; /* * Set a timer to detect whether this sleep is much @@ -400,28 +382,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) */ timer_us = 2 * (data->predicted_us + MAX_DEVIATION); - perfect_us = perfect_cstate_ms * 1000; - if (repeat && (4 * timer_us < data->expected_us)) { RCU_NONIDLE(hrtimer_start(hrtmr, ns_to_ktime(1000 * timer_us), HRTIMER_MODE_REL_PINNED)); /* In repeat case, menu hrtimer is started */ per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; - } else if (perfect_us < data->expected_us) { - /* - * The next timer is long. This could be because - * we did not make a useful prediction. - * In that case, it makes sense to re-enter - * into a deeper C-state after some time. - */ - RCU_NONIDLE(hrtimer_start(hrtmr, - ns_to_ktime(1000 * timer_us), - HRTIMER_MODE_REL_PINNED)); - /* In general case, menu hrtimer is started */ - per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL; } - } return data->last_state_idx; -- cgit v0.10.2 From 148519120c6d1f19ad53349683aeae9f228b0b8d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 27 Jul 2013 01:41:34 +0200 Subject: Revert "cpuidle: Quickly notice prediction failure for repeat mode" Revert commit 69a37bea (cpuidle: Quickly notice prediction failure for repeat mode), because it has been identified as the source of a significant performance regression in v3.8 and later as explained by Jeremy Eder: We believe we've identified a particular commit to the cpuidle code that seems to be impacting performance of variety of workloads. The simplest way to reproduce is using netperf TCP_RR test, so we're using that, on a pair of Sandy Bridge based servers. We also have data from a large database setup where performance is also measurably/positively impacted, though that test data isn't easily share-able. Included below are test results from 3 test kernels: kernel reverts ----------------------------------------------------------- 1) vanilla upstream (no reverts) 2) perfteam2 reverts e11538d1f03914eb92af5a1a378375c05ae8520c 3) test reverts 69a37beabf1f0a6705c08e879bdd5d82ff6486c4 e11538d1f03914eb92af5a1a378375c05ae8520c In summary, netperf TCP_RR numbers improve by approximately 4% after reverting 69a37beabf1f0a6705c08e879bdd5d82ff6486c4. When 69a37beabf1f0a6705c08e879bdd5d82ff6486c4 is included, C0 residency never seems to get above 40%. Taking that patch out gets C0 near 100% quite often, and performance increases. The below data are histograms representing the %c0 residency @ 1-second sample rates (using turbostat), while under netperf test. - If you look at the first 4 histograms, you can see %c0 residency almost entirely in the 30,40% bin. - The last pair, which reverts 69a37beabf1f0a6705c08e879bdd5d82ff6486c4, shows %c0 in the 80,90,100% bins. Below each kernel name are netperf TCP_RR trans/s numbers for the particular kernel that can be disclosed publicly, comparing the 3 test kernels. We ran a 4th test with the vanilla kernel where we've also set /dev/cpu_dma_latency=0 to show overall impact boosting single-threaded TCP_RR performance over 11% above baseline. 3.10-rc2 vanilla RX + c0 lock (/dev/cpu_dma_latency=0): TCP_RR trans/s 54323.78 ----------------------------------------------------------- 3.10-rc2 vanilla RX (no reverts) TCP_RR trans/s 48192.47 Receiver %c0 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 0]: 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 59]: *********************************************************** 40.0000 - 50.0000 [ 1]: * 50.0000 - 60.0000 [ 0]: 60.0000 - 70.0000 [ 0]: 70.0000 - 80.0000 [ 0]: 80.0000 - 90.0000 [ 0]: 90.0000 - 100.0000 [ 0]: Sender %c0 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 0]: 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 11]: *********** 40.0000 - 50.0000 [ 49]: ************************************************* 50.0000 - 60.0000 [ 0]: 60.0000 - 70.0000 [ 0]: 70.0000 - 80.0000 [ 0]: 80.0000 - 90.0000 [ 0]: 90.0000 - 100.0000 [ 0]: ----------------------------------------------------------- 3.10-rc2 perfteam2 RX (reverts commit e11538d1f03914eb92af5a1a378375c05ae8520c) TCP_RR trans/s 49698.69 Receiver %c0 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 1]: * 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 59]: *********************************************************** 40.0000 - 50.0000 [ 0]: 50.0000 - 60.0000 [ 0]: 60.0000 - 70.0000 [ 0]: 70.0000 - 80.0000 [ 0]: 80.0000 - 90.0000 [ 0]: 90.0000 - 100.0000 [ 0]: Sender %c0 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 0]: 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 2]: ** 40.0000 - 50.0000 [ 58]: ********************************************************** 50.0000 - 60.0000 [ 0]: 60.0000 - 70.0000 [ 0]: 70.0000 - 80.0000 [ 0]: 80.0000 - 90.0000 [ 0]: 90.0000 - 100.0000 [ 0]: ----------------------------------------------------------- 3.10-rc2 test RX (reverts 69a37beabf1f0a6705c08e879bdd5d82ff6486c4 and e11538d1f03914eb92af5a1a378375c05ae8520c) TCP_RR trans/s 47766.95 Receiver %c0 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 1]: * 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 27]: *************************** 40.0000 - 50.0000 [ 2]: ** 50.0000 - 60.0000 [ 0]: 60.0000 - 70.0000 [ 2]: ** 70.0000 - 80.0000 [ 0]: 80.0000 - 90.0000 [ 0]: 90.0000 - 100.0000 [ 28]: **************************** Sender: 0.0000 - 10.0000 [ 1]: * 10.0000 - 20.0000 [ 0]: 20.0000 - 30.0000 [ 0]: 30.0000 - 40.0000 [ 11]: *********** 40.0000 - 50.0000 [ 0]: 50.0000 - 60.0000 [ 1]: * 60.0000 - 70.0000 [ 0]: 70.0000 - 80.0000 [ 3]: *** 80.0000 - 90.0000 [ 7]: ******* 90.0000 - 100.0000 [ 38]: ************************************** These results demonstrate gaining back the tendency of the CPU to stay in more responsive, performant C-states (and thus yield measurably better performance), by reverting commit 69a37beabf1f0a6705c08e879bdd5d82ff6486c4. Requested-by: Jeremy Eder Tested-by: Len Brown Cc: 3.8+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index b69a87e..bc580b6 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -28,13 +28,6 @@ #define MAX_INTERESTING 50000 #define STDDEV_THRESH 400 -/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */ -#define MAX_DEVIATION 60 - -static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer); -static DEFINE_PER_CPU(int, hrtimer_status); -/* menu hrtimer mode */ -enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT}; /* * Concepts and ideas behind the menu governor @@ -198,42 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor) return div_u64(dividend + (divisor / 2), divisor); } -/* Cancel the hrtimer if it is not triggered yet */ -void menu_hrtimer_cancel(void) -{ - int cpu = smp_processor_id(); - struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); - - /* The timer is still not time out*/ - if (per_cpu(hrtimer_status, cpu)) { - hrtimer_cancel(hrtmr); - per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; - } -} -EXPORT_SYMBOL_GPL(menu_hrtimer_cancel); - -/* Call back for hrtimer is triggered */ -static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) -{ - int cpu = smp_processor_id(); - - per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; - - return HRTIMER_NORESTART; -} - /* * Try detecting repeating patterns by keeping track of the last 8 * intervals, and checking if the standard deviation of that set * of points is below a threshold. If it is... then use the * average of these 8 points as the estimated value. */ -static u32 get_typical_interval(struct menu_device *data) +static void get_typical_interval(struct menu_device *data) { int i = 0, divisor = 0; uint64_t max = 0, avg = 0, stddev = 0; int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ - unsigned int ret = 0; again: @@ -274,16 +242,13 @@ again: if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) || stddev <= 20) { data->predicted_us = avg; - ret = 1; - return ret; + return; } else if ((divisor * 4) > INTERVALS * 3) { /* Exclude the max interval */ thresh = max - 1; goto again; } - - return ret; } /** @@ -298,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) int i; int multiplier; struct timespec t; - int repeat = 0, low_predicted = 0; - int cpu = smp_processor_id(); - struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); if (data->needs_update) { menu_update(drv, dev); @@ -335,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); - repeat = get_typical_interval(data); + get_typical_interval(data); /* * We want to default to C1 (hlt), not to busy polling @@ -356,10 +318,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (s->disabled || su->disable) continue; - if (s->target_residency > data->predicted_us) { - low_predicted = 1; + if (s->target_residency > data->predicted_us) continue; - } if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) @@ -369,28 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->exit_us = s->exit_latency; } - /* not deepest C-state chosen for low predicted residency */ - if (low_predicted) { - unsigned int timer_us = 0; - - /* - * Set a timer to detect whether this sleep is much - * longer than repeat mode predicted. If the timer - * triggers, the code will evaluate whether to put - * the CPU into a deeper C-state. - * The timer is cancelled on CPU wakeup. - */ - timer_us = 2 * (data->predicted_us + MAX_DEVIATION); - - if (repeat && (4 * timer_us < data->expected_us)) { - RCU_NONIDLE(hrtimer_start(hrtmr, - ns_to_ktime(1000 * timer_us), - HRTIMER_MODE_REL_PINNED)); - /* In repeat case, menu hrtimer is started */ - per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; - } - } - return data->last_state_idx; } @@ -481,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); - struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu); - hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - t->function = menu_hrtimer_notify; memset(data, 0, sizeof(struct menu_device)); diff --git a/include/linux/tick.h b/include/linux/tick.h index 9180f4b..62bd8b7 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -174,10 +174,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk) { } #endif -# ifdef CONFIG_CPU_IDLE_GOV_MENU -extern void menu_hrtimer_cancel(void); -# else -static inline void menu_hrtimer_cancel(void) {} -# endif /* CONFIG_CPU_IDLE_GOV_MENU */ - #endif diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index e80183f..e77edc9 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void) { struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); - if (ts->inidle) { - /* Cancel the timer because CPU already waken up from the C-states*/ - menu_hrtimer_cancel(); + if (ts->inidle) __tick_nohz_idle_enter(ts); - } else { + else tick_nohz_full_stop_tick(ts); - } } /** @@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void) ts->inidle = 0; - /* Cancel the timer because CPU already waken up from the C-states*/ - menu_hrtimer_cancel(); if (ts->idle_active || ts->tick_stopped) now = ktime_get(); -- cgit v0.10.2 From a8d30608eaed6cc759b8e2e8a8bbbb42591f797f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 29 Jul 2013 15:10:22 +0530 Subject: ALSA: compress: fix the return value for SNDRV_COMPRESS_VERSION the return value of SNDRV_COMPRESS_VERSION always return default -ENOTTY as the return value was never updated for this call assign return value from put_user() Reported-by: Haynes CC: stable@vger.kernel.org Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 99db892..9896954 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -743,7 +743,7 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) mutex_lock(&stream->device->lock); switch (_IOC_NR(cmd)) { case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): - put_user(SNDRV_COMPRESS_VERSION, + retval = put_user(SNDRV_COMPRESS_VERSION, (int __user *)arg) ? -EFAULT : 0; break; case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): -- cgit v0.10.2 From d7ead0c3c27ef601964d1428066fac932070af7f Mon Sep 17 00:00:00 2001 From: Aurelien Chartier Date: Tue, 9 Jul 2013 14:29:35 +0100 Subject: xenbus: frontend resume cleanup Only create the delayed resume workqueue if we are running in the same domain as xenstored and issue a warning if the workqueue creation fails. Move the work initialization to the device probe so it is done only once. Signed-off-by: Aurelien Chartier Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: David Vrabel diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 6ed8a9d..34b20bf 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev) return -EFAULT; } - INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume); queue_work(xenbus_frontend_wq, &xdev->work); return 0; @@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev) return xenbus_dev_resume(dev); } +static int xenbus_frontend_dev_probe(struct device *dev) +{ + if (xen_store_domain_type == XS_LOCAL) { + struct xenbus_device *xdev = to_xenbus_device(dev); + INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume); + } + + return xenbus_dev_probe(dev); +} + static const struct dev_pm_ops xenbus_pm_ops = { .suspend = xenbus_dev_suspend, .resume = xenbus_frontend_dev_resume, @@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = { .name = "xen", .match = xenbus_match, .uevent = xenbus_uevent_frontend, - .probe = xenbus_dev_probe, + .probe = xenbus_frontend_dev_probe, .remove = xenbus_dev_remove, .shutdown = xenbus_dev_shutdown, .dev_attrs = xenbus_dev_attrs, @@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void) register_xenstore_notifier(&xenstore_notifier); - xenbus_frontend_wq = create_workqueue("xenbus_frontend"); + if (xen_store_domain_type == XS_LOCAL) { + xenbus_frontend_wq = create_workqueue("xenbus_frontend"); + if (!xenbus_frontend_wq) + pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n"); + } return 0; } -- cgit v0.10.2 From f21407179ccd0dec35f4580052c26ea923c28ac9 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Mon, 22 Jul 2013 22:40:58 +0100 Subject: xen/arm64: Don't compile cpu hotplug On ARM64, when CONFIG_XEN=y, the compilation will fail because CPU hotplug is not yet supported with XEN. For now, disable it. Signed-off-by: Julien Grall Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Mark Rutland diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index eabd0ee..fc37c49 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,4 +1,4 @@ -ifneq ($(CONFIG_ARM),y) +ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),) obj-y += manage.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o endif -- cgit v0.10.2 From 9e7fd145b691127cfd48ab8c05cc1aa6d35b57ad Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Tue, 23 Jul 2013 16:21:28 +0100 Subject: xen/arm: enable PV control for ARM Enable lifecyle management (reboot, shutdown...) from the toolstack for ARM guests. Signed-off-by: Julien Grall Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Stefano Stabellini diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index fc37c49..14fe79d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,9 +1,8 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),) -obj-y += manage.o obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o endif obj-$(CONFIG_X86) += fallback.o -obj-y += grant-table.o features.o events.o balloon.o +obj-y += grant-table.o features.o events.o balloon.o manage.o obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) -- cgit v0.10.2 From 1deb57042fe2bd14cd7d4687f3c9418d26862053 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Jul 2013 08:50:28 +0100 Subject: ASoC: bfin-ac97: Fix prototype error following AC'97 refactoring As part of the multiplatform refactoring for AC'97 the AC'97 bus ops were staticised meaning that the prototype (which was never needed) conflicts with the declaration causing build failures. Signed-off-by: Mark Brown Acked-by: Lars-Peter Clausen diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 15c635e..0c3e22d 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h @@ -9,7 +9,6 @@ #ifndef _BF5XX_AC97_H #define _BF5XX_AC97_H -extern struct snd_ac97_bus_ops bf5xx_ac97_ops; extern struct snd_ac97 *ac97; /* Frame format in memory, only support stereo currently */ struct ac97_frame { -- cgit v0.10.2 From be348790e46cf3783f265b0ecf9fa9dc68bd6f15 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 4 Jul 2013 21:35:00 +0800 Subject: drm/exynos: exynos_drm_ipp: fix return value check In case of error, the function ipp_find_obj() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Reviewed-by: Tomasz Figa Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index b1ef8e7..0eb8538 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -342,10 +342,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, */ ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, prop_list->ipp_id); - if (!ippdrv) { + if (IS_ERR(ippdrv)) { DRM_ERROR("not found ipp%d driver.\n", prop_list->ipp_id); - return -EINVAL; + return PTR_ERR(ippdrv); } prop_list = ippdrv->prop_list; @@ -970,9 +970,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, /* find command node */ c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, qbuf->prop_id); - if (!c_node) { + if (IS_ERR(c_node)) { DRM_ERROR("failed to get command node.\n"); - return -EFAULT; + return PTR_ERR(c_node); } /* buffer control */ @@ -1106,9 +1106,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, cmd_ctrl->prop_id); - if (!c_node) { + if (IS_ERR(c_node)) { DRM_ERROR("invalid command node list.\n"); - return -EINVAL; + return PTR_ERR(c_node); } if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, -- cgit v0.10.2 From de1d3677017a1d58419722b60564cb56bd9462c3 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 22 Jul 2013 20:51:42 +0900 Subject: drm/exynos: fix module build error This patch removes all MODULE_DEVICE_TABLE declarations. Exynos drm drivers don't need to create MODULE_DEVICE_TABLE yet because all devices of Exynos drm include in one SoC so they cannot be plugged in as of now. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 3e106be..5dba79e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -130,7 +130,6 @@ static const struct of_device_id fimd_driver_dt_match[] = { .data = &exynos5_fimd_driver_data }, {}, }; -MODULE_DEVICE_TABLE(of, fimd_driver_dt_match); #endif static inline struct fimd_driver_data *drm_fimd_get_driver_data( @@ -1082,7 +1081,6 @@ static struct platform_device_id fimd_driver_ids[] = { }, {}, }; -MODULE_DEVICE_TABLE(platform, fimd_driver_ids); static const struct dev_pm_ops fimd_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 42a5a54..4722662 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1521,7 +1521,6 @@ static const struct of_device_id exynos_g2d_match[] = { { .compatible = "samsung,exynos5250-g2d" }, {}, }; -MODULE_DEVICE_TABLE(of, exynos_g2d_match); #endif struct platform_driver g2d_driver = { -- cgit v0.10.2 From 89f8b85ecd31a678a17d419327000a60b74b2ed7 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Wed, 24 Jul 2013 13:40:12 +0900 Subject: drm/exynos: consider common clock framework to g2d driver. This patch just changes clk_enable/disable to clk_prepare_enable/clk_disable_unprepare, and adds related exception codes. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 4722662..f81cfd4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -806,9 +806,20 @@ static void g2d_dma_start(struct g2d_data *g2d, struct g2d_cmdlist_node *node = list_first_entry(&runqueue_node->run_cmdlist, struct g2d_cmdlist_node, list); + int ret; + + ret = pm_runtime_get_sync(g2d->dev); + if (ret < 0) { + dev_warn(g2d->dev, "failed pm power on.\n"); + return; + } - pm_runtime_get_sync(g2d->dev); - clk_enable(g2d->gate_clk); + ret = clk_prepare_enable(g2d->gate_clk); + if (ret < 0) { + dev_warn(g2d->dev, "failed to enable clock.\n"); + pm_runtime_put_sync(g2d->dev); + return; + } writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR); writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND); @@ -861,7 +872,7 @@ static void g2d_runqueue_worker(struct work_struct *work) runqueue_work); mutex_lock(&g2d->runqueue_mutex); - clk_disable(g2d->gate_clk); + clk_disable_unprepare(g2d->gate_clk); pm_runtime_put_sync(g2d->dev); complete(&g2d->runqueue_node->complete); -- cgit v0.10.2 From db70d16ef63dbd412a974c893c52ee5ad0777d21 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 26 Jul 2013 13:29:19 +0530 Subject: drm/exynos: Remove module.h header inclusion Remove module.h header file inclusion from files since they do not use/refer to any code from that file. Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c index 95c75ed..30ef41b 100644 --- a/drivers/gpu/drm/exynos/exynos_ddc.c +++ b/drivers/gpu/drm/exynos/exynos_ddc.c @@ -15,7 +15,6 @@ #include #include -#include #include "exynos_drm_drv.h" diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 61b094f..6e047bd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -12,7 +12,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 5dba79e..1c263da 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index f81cfd4..eddea49 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 472e3b2..90b8a1a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -12,7 +12,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index aaa550d..8d3bc01 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -15,7 +15,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 0eb8538..d2b6ab4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -12,7 +12,6 @@ * */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 427640a..49669aa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 41cc74d..c57c565 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 62ef597..2f5c694 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c index ef04255..6e320ae 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c +++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c @@ -15,7 +15,6 @@ #include #include -#include #include "exynos_drm_drv.h" #include "exynos_hdmi.h" diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 42ffb71..c9a137c 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include -- cgit v0.10.2 From dec23dca5a9ca4b9eb2fb66926f567889028b904 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 29 Jul 2013 13:09:56 +0300 Subject: usb: chipidea: cast PORTSC_PTS and DEVLC_PTS macros Fix the following build warnings on x86: drivers/usb/chipidea/core.c: In function 'hw_phymode_configure': drivers/usb/chipidea/core.c:226:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] drivers/usb/chipidea/core.c:230:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] drivers/usb/chipidea/core.c:243:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] drivers/usb/chipidea/core.c:246:3: warning: large integer implicitly truncated to unsigned type [-Woverflow] Reported-by: Felipe Balbi Signed-off-by: Fabio Estevam Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index aefa026..1b23e35 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -50,7 +50,7 @@ #define PORTSC_PTC (0x0FUL << 16) /* PTS and PTW for non lpm version only */ #define PORTSC_PTS(d) \ - ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0)) + (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0)) #define PORTSC_PTW BIT(28) #define PORTSC_STS BIT(29) @@ -59,7 +59,7 @@ #define DEVLC_PSPD_HS (0x02UL << 25) #define DEVLC_PTW BIT(27) #define DEVLC_STS BIT(28) -#define DEVLC_PTS(d) (((d) & 0x7) << 29) +#define DEVLC_PTS(d) (u32)(((d) & 0x7) << 29) /* Encoding for DEVLC_PTS and PORTSC_PTS */ #define PTS_UTMI 0 -- cgit v0.10.2 From 972a6c5d56b42d6dd326867d5974ffa58383ec53 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 29 Jul 2013 13:09:57 +0300 Subject: usb: chipidea: fix the build error with randconfig Using below configs, the compile will have error: ERROR: "ehci_init_driver" undefined! .config: CONFIG_USB_CHIPIDEA=m CONFIG_USB_CHIPIDEA_HOST=y CONFIG_USB_CHIPIDEA_DEBUG=y The reason is chipidea host uses symbol from ehci, but ehci is not compiled. Let the chipidea host depend on ehci even it is built as module. Signed-off-by: Peter Chen Signed-off-by: Alexander Shishkin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index eb2aa2e..d1bd8ef 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -12,7 +12,7 @@ if USB_CHIPIDEA config USB_CHIPIDEA_UDC bool "ChipIdea device controller" - depends on USB_GADGET=y || USB_CHIPIDEA=m + depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m) help Say Y here to enable device controller functionality of the ChipIdea driver. @@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC config USB_CHIPIDEA_HOST bool "ChipIdea host controller" depends on USB=y - depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m + depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m) select USB_EHCI_ROOT_HUB_TT help Say Y here to enable host controller functionality of the -- cgit v0.10.2 From 1a7f0e3c4fff449f6dd08787beb98a8e57d8cdc7 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 24 Jul 2013 10:09:43 -0700 Subject: x86/mce: Fix mce regression from recent cleanup In commit 33d7885b594e169256daef652e8d3527b2298e75 x86/mce: Update MCE severity condition check We simplified the rules to recognise each classification of recoverable machine check combining the instruction and data fetch rules into a single entry based on clarifications in the June 2013 SDM that all recoverable events would be reported on the unaffected processor with MCG_STATUS.EIPV=0 and MCG_STATUS.RIPV=1. Unfortunately the simplified rule has a couple of bugs. Fix them here. Acked-by: Naveen N. Rao Signed-off-by: Tony Luck diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index e2703520..c370e1c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -111,8 +111,8 @@ static struct severity { #ifdef CONFIG_MEMORY_FAILURE MCESEV( KEEP, "Action required but unaffected thread is continuable", - SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR), - MCGMASK(MCG_STATUS_RIPV, MCG_STATUS_RIPV) + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR), + MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV) ), MCESEV( AR, "Action required: data load error in a user process", -- cgit v0.10.2 From e2288b66fe7ff0288382b2af671b4da558b44472 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sun, 28 Jul 2013 13:17:22 +0200 Subject: rt2x00: fix stop queue Since we clear QUEUE_STARTED in rt2x00queue_stop_queue(), following call to rt2x00queue_pause_queue() reduce to noop, i.e we do not stop queue in mac80211. To fix that introduce rt2x00queue_pause_queue_nocheck() function, which will stop queue in mac80211 directly. Note that rt2x00_start_queue() explicitly set QUEUE_PAUSED bit. Note also that reordering operations i.e. first call to rt2x00queue_pause_queue() and then clear QUEUE_STARTED bit, will race with rt2x00queue_unpause_queue(), so calling ieee80211_stop_queue() directly is the only available solution to fix the problem without major rework. Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 6c0a91f..aa95c6c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index) spin_unlock_irqrestore(&queue->index_lock, irqflags); } -void rt2x00queue_pause_queue(struct data_queue *queue) +void rt2x00queue_pause_queue_nocheck(struct data_queue *queue) { - if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || - !test_bit(QUEUE_STARTED, &queue->flags) || - test_and_set_bit(QUEUE_PAUSED, &queue->flags)) - return; - switch (queue->qid) { case QID_AC_VO: case QID_AC_VI: @@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue) break; } } +void rt2x00queue_pause_queue(struct data_queue *queue) +{ + if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) || + !test_bit(QUEUE_STARTED, &queue->flags) || + test_and_set_bit(QUEUE_PAUSED, &queue->flags)) + return; + + rt2x00queue_pause_queue_nocheck(queue); +} EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue); void rt2x00queue_unpause_queue(struct data_queue *queue) @@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue) return; } - rt2x00queue_pause_queue(queue); + rt2x00queue_pause_queue_nocheck(queue); queue->rt2x00dev->ops->lib->stop_queue(queue); -- cgit v0.10.2 From fed1f1ed90bce42ea010e2904cbc04e7b8304940 Mon Sep 17 00:00:00 2001 From: "Rick Farina (Zero_Chaos)" Date: Mon, 29 Jul 2013 15:17:59 -0400 Subject: USB: serial: ftdi_sio: add more RT Systems ftdi devices RT Systems makes many usb serial cables based on the ftdi_sio driver for programming various amateur radios. This patch is a full listing of their current product offerings and should allow these cables to all be recognized. Signed-off-by: Rick Farina (Zero_Chaos) Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 7260ec6..b65e657 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -735,9 +735,34 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) }, + { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 6dd7925..1b8af46 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -815,11 +815,35 @@ /* * RT Systems programming cables for various ham radios */ -#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ -#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ -#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ -#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ - +#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ +#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */ +#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */ +#define RTSYSTEMS_USB_57A_PID 0x9e51 /* USB-57A USB to 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_57B_PID 0x9e52 /* USB-57B USB to extended 4pin 3.5mm plug */ +#define RTSYSTEMS_USB_29A_PID 0x9e53 /* USB-29A USB to 3.5mm stereo plug */ +#define RTSYSTEMS_USB_29B_PID 0x9e54 /* USB-29B USB to 6 pin mini din */ +#define RTSYSTEMS_USB_29F_PID 0x9e55 /* USB-29F USB to 6 pin modular plug */ +#define RTSYSTEMS_USB_62B_PID 0x9e56 /* USB-62B USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_S01_PID 0x9e57 /* USB-RTS01 USB to 3.5 mm stereo plug*/ +#define RTSYSTEMS_USB_63_PID 0x9e58 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_29C_PID 0x9e59 /* USB-29C USB to 4 pin modular plug*/ +#define RTSYSTEMS_USB_81B_PID 0x9e5A /* USB-81 USB to 8 pin mini din plug*/ +#define RTSYSTEMS_USB_82B_PID 0x9e5B /* USB-82 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_K5D_PID 0x9e5C /* USB-K5D USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_K4Y_PID 0x9e5D /* USB-K4Y USB to 2.5/3.5 mm plugs*/ +#define RTSYSTEMS_USB_K5G_PID 0x9e5E /* USB-K5G USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_S05_PID 0x9e5F /* USB-RTS05 USB to 2.5 mm stereo plug*/ +#define RTSYSTEMS_USB_60_PID 0x9e60 /* USB-60 USB to 6 pin din*/ +#define RTSYSTEMS_USB_61_PID 0x9e61 /* USB-61 USB to 6 pin mini din*/ +#define RTSYSTEMS_USB_62_PID 0x9e62 /* USB-62 USB to 8 pin mini din*/ +#define RTSYSTEMS_USB_63B_PID 0x9e63 /* USB-63 USB to 9 pin female*/ +#define RTSYSTEMS_USB_64_PID 0x9e64 /* USB-64 USB to 9 pin male*/ +#define RTSYSTEMS_USB_65_PID 0x9e65 /* USB-65 USB to 9 pin female null modem*/ +#define RTSYSTEMS_USB_92_PID 0x9e66 /* USB-92 USB to 12 pin plug*/ +#define RTSYSTEMS_USB_92D_PID 0x9e67 /* USB-92D USB to 12 pin plug data*/ +#define RTSYSTEMS_USB_W5R_PID 0x9e68 /* USB-W5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_A5R_PID 0x9e69 /* USB-A5R USB to 8 pin modular plug*/ +#define RTSYSTEMS_USB_PW1_PID 0x9e6A /* USB-PW1 USB to 8 pin modular plug*/ /* * Physik Instrumente -- cgit v0.10.2 From 7d61d835824f73dc4097b51f800382467c8049c5 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Jul 2013 13:26:05 -0400 Subject: drm/radeon: fix audio dto programming on DCE4+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to set the dto source before setting the dividers otherwise we may get stability problems with the dto leading to audio playback problems. Signed-off-by: Alex Deucher Reviewed-by: Christian König Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index b0d3fb3..bb9ea36 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -157,9 +157,9 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ + WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); - WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); } -- cgit v0.10.2 From 489bc476b4c2b3097fe9e980379bbbab260a6156 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Jul 2013 18:05:07 -0400 Subject: drm/radeon/dpm: fix display gap programming on SI Need to set the DISP*_GAP fields as well as the DISP*_GAP_MCHG fields. Same as on previous asics. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 73aaa2e..6ecbb87 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -3620,8 +3620,12 @@ static void si_enable_display_gap(struct radeon_device *rdev) { u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL); + tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK); + tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) | + DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE)); + tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK); - tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) | + tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) | DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE)); WREG32(CG_DISPLAY_GAP_CNTL, tmp); } -- cgit v0.10.2 From f44a0120ef07cc9a1f36ab86751ec2b0598d7a2b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Jul 2013 18:18:32 -0400 Subject: drm/radeon/dpm: fix si_calculate_memory_refresh_rate() Update alogorithm as per internal advice. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 6ecbb87..80c1f50 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -37,8 +37,6 @@ #define SMC_RAM_END 0x20000 -#define DDR3_DRAM_ROWS 0x2000 - #define SCLK_MIN_DEEPSLEEP_FREQ 1350 static const struct si_cac_config_reg cac_weights_tahiti[] = @@ -4040,16 +4038,15 @@ static int si_force_switch_to_arb_f0(struct radeon_device *rdev) static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev, u32 engine_clock) { - struct rv7xx_power_info *pi = rv770_get_pi(rdev); u32 dram_rows; u32 dram_refresh_rate; u32 mc_arb_rfsh_rate; u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT; - if (pi->mem_gddr5) - dram_rows = 1 << (tmp + 10); + if (tmp >= 4) + dram_rows = 16384; else - dram_rows = DDR3_DRAM_ROWS; + dram_rows = 1 << (tmp + 10); dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3); mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64; -- cgit v0.10.2 From 46348dc29bc936360057e9b41003274284ec0a47 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Jul 2013 18:21:02 -0400 Subject: drm/radeon/dpm: fix powertune handling for pci id 0x6835 0x6835 should be treated as a cape verde pro. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 80c1f50..994f9e5 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1939,6 +1939,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev) case 0x683B: case 0x683F: case 0x6829: + case 0x6835: si_pi->cac_weights = cac_weights_cape_verde_pro; si_pi->dte_data = dte_data_cape_verde; break; -- cgit v0.10.2 From b2d70917e4b9fc5bddfbd025bfb1f15185e74971 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 27 Jul 2013 17:53:25 -0400 Subject: drm/radeon: properly handle cg on asics without UVD Don't try and enable clockgating if the asic doesn't have UVD. Use rdev->has_uvd rather than using local checks. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index d325280..1d656f7 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5215,14 +5215,12 @@ static void si_enable_mc_ls(struct radeon_device *rdev, static void si_init_cg(struct radeon_device *rdev) { - bool has_uvd = true; - si_enable_mgcg(rdev, true); si_enable_cgcg(rdev, true); /* disable MC LS on Tahiti */ if (rdev->family == CHIP_TAHITI) si_enable_mc_ls(rdev, false); - if (has_uvd) { + if (rdev->has_uvd) { si_enable_uvd_mgcg(rdev, true); si_init_uvd_internal_cg(rdev); } @@ -5230,9 +5228,7 @@ static void si_init_cg(struct radeon_device *rdev) static void si_fini_cg(struct radeon_device *rdev) { - bool has_uvd = true; - - if (has_uvd) + if (rdev->has_uvd) si_enable_uvd_mgcg(rdev, false); si_enable_cgcg(rdev, false); si_enable_mgcg(rdev, false); -- cgit v0.10.2 From 20fab6415cfe33172dfaea1595a2739bdea5f57e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 28 Jul 2013 12:33:56 -0400 Subject: drm/radeon/atom: fix fb when fetching engine params For correctness. The fb divider isn't actually used in any of the relevant dpm code. It's calculated from the other parameters. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index e3f3e88..4ccd61f 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2782,7 +2782,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev, ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false; dividers->enable_dithen = (args.v3.ucCntlFlag & ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true; - dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); + dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv); dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac); dividers->ref_div = args.v3.ucRefDiv; dividers->vco_mode = (args.v3.ucCntlFlag & -- cgit v0.10.2 From f86d0269b471d88c9c06da4972f9145f978a0e5a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Jul 2013 10:45:27 -0400 Subject: drm/radeon/dpm: fix forcing performance state to low on cayman Need to program EnabledLevels to 1 to force the low state. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 559cf24..4f9b9bc 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -1054,10 +1054,6 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd int ni_dpm_force_performance_level(struct radeon_device *rdev, enum radeon_dpm_forced_level level) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; - struct ni_ps *ps = ni_get_ps(rps); - u32 levels; - if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) return -EINVAL; @@ -1068,8 +1064,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev, if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) return -EINVAL; - levels = ps->performance_level_count - 1; - if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) + if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK) return -EINVAL; } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) -- cgit v0.10.2 From 3652f00591982b15f0702dd90e4e5f0ddcfe7f8b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 29 Jul 2013 11:51:25 -0400 Subject: drm/radeon/si: disable cgcg and pg for now Coarse grain clockgating causes problems with reclocking on some cards and powergating (verde only) causes problems with ring initialization. The proper fix (restructuring the init sequences) is too invasive for 3.11 so just disable them for now. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1d656f7..6ca9046 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5216,7 +5216,7 @@ static void si_enable_mc_ls(struct radeon_device *rdev, static void si_init_cg(struct radeon_device *rdev) { si_enable_mgcg(rdev, true); - si_enable_cgcg(rdev, true); + si_enable_cgcg(rdev, false); /* disable MC LS on Tahiti */ if (rdev->family == CHIP_TAHITI) si_enable_mc_ls(rdev, false); @@ -5237,11 +5237,11 @@ static void si_fini_cg(struct radeon_device *rdev) static void si_init_pg(struct radeon_device *rdev) { bool has_pg = false; - +#if 0 /* only cape verde supports PG */ if (rdev->family == CHIP_VERDE) has_pg = true; - +#endif if (has_pg) { si_init_ao_cu_mask(rdev); si_init_dma_pg(rdev); -- cgit v0.10.2 From d05f7e700a3a47eeb7dbe236d2680381f5b5edcb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 28 Jul 2013 18:26:38 -0400 Subject: drm/radeon/dpm: disable cac setup on SI Disable cac setup on SI for now since it causes strange performance level restrictions on certain cards. I suspect there may be issues with some of the 64 bit fixed point double emulation that is used to set up those parameters. I need to double check the math before this can be re-enabled. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 994f9e5..e8ee685 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1929,6 +1929,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev) si_pi->cac_override = cac_override_pitcairn; si_pi->powertune_data = &powertune_data_pitcairn; si_pi->dte_data = dte_data_pitcairn; + break; } } else if (rdev->family == CHIP_VERDE) { si_pi->lcac_config = lcac_cape_verde; @@ -2041,7 +2042,8 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev) ni_pi->enable_sq_ramping = false; si_pi->enable_dte = false; - if (si_pi->powertune_data->enable_powertune_by_default) { + /* XXX: fix me */ + if (0/*si_pi->powertune_data->enable_powertune_by_default*/) { ni_pi->enable_power_containment= true; ni_pi->enable_cac = true; if (si_pi->dte_data.enable_dte_by_default) { -- cgit v0.10.2 From 63f22d0e98cf74adf4ecfb25099607239b00c751 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 27 Jul 2013 17:50:26 -0400 Subject: drm/radeon/dpm: fix and enable reclocking on SI The SMC interface changed compared to Cayman and previous asics. Set the enabled levels properly and enable reclocking by default when dpm is enabled. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index e8ee685..1604a87 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -3238,10 +3238,10 @@ int si_dpm_force_performance_level(struct radeon_device *rdev, { struct radeon_ps *rps = rdev->pm.dpm.current_ps; struct ni_ps *ps = ni_get_ps(rps); - u32 levels; + u32 levels = ps->performance_level_count; if (level == RADEON_DPM_FORCED_LEVEL_HIGH) { - if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) return -EINVAL; if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK) @@ -3250,14 +3250,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev, if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) return -EINVAL; - levels = ps->performance_level_count - 1; - if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK) return -EINVAL; } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) { if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK) return -EINVAL; - if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK) + if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK) return -EINVAL; } @@ -6017,16 +6016,11 @@ int si_dpm_set_power_state(struct radeon_device *rdev) return ret; } -#if 0 - /* XXX */ ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO); if (ret) { DRM_ERROR("si_dpm_force_performance_level failed\n"); return ret; } -#else - rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO; -#endif return 0; } -- cgit v0.10.2 From 2a99859932281ed6c2ecdd988855f8f6838f6743 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 30 Jul 2013 00:32:00 +0200 Subject: cpufreq: Fix cpufreq driver module refcount balance after suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since cpufreq_cpu_put() called by __cpufreq_remove_dev() drops the driver module refcount, __cpufreq_remove_dev() causes that refcount to become negative for the cpufreq driver after a suspend/resume cycle. This is not the only bad thing that happens there, however, because kobject_put() should only be called for the policy kobject at this point if the CPU is not the last one for that policy. Namely, if the given CPU is the last one for that policy, the policy kobject's refcount should be 1 at this point, as set by cpufreq_add_dev_interface(), and only needs to be dropped once for the kobject to go away. This actually happens under the cpu == 1 check, so it need not be done before by cpufreq_cpu_put(). On the other hand, if the given CPU is not the last one for that policy, this means that cpufreq_add_policy_cpu() has been called at least once for that policy and cpufreq_cpu_get() has been called for it too. To balance that cpufreq_cpu_get(), we need to call cpufreq_cpu_put() in that case. Thus, to fix the described problem and keep the reference counters balanced in both cases, move the cpufreq_cpu_get() call in __cpufreq_remove_dev() to the code path executed only for CPUs that share the policy with other CPUs. Reported-and-tested-by: Toralf Förster Signed-off-by: Rafael J. Wysocki Reviewed-by: Srivatsa S. Bhat Cc: 3.10+ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a4ad733..f0a5e2b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1177,14 +1177,11 @@ static int __cpufreq_remove_dev(struct device *dev, __func__, cpu_dev->id, cpu); } - if ((cpus == 1) && (cpufreq_driver->target)) - __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); - - pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); - cpufreq_cpu_put(data); - /* If cpu is last user of policy, free policy */ if (cpus == 1) { + if (cpufreq_driver->target) + __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); + lock_policy_rwsem_read(cpu); kobj = &data->kobj; cmp = &data->kobj_unregister; @@ -1205,9 +1202,13 @@ static int __cpufreq_remove_dev(struct device *dev, free_cpumask_var(data->related_cpus); free_cpumask_var(data->cpus); kfree(data); - } else if (cpufreq_driver->target) { - __cpufreq_governor(data, CPUFREQ_GOV_START); - __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); + } else { + pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); + cpufreq_cpu_put(data); + if (cpufreq_driver->target) { + __cpufreq_governor(data, CPUFREQ_GOV_START); + __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); + } } per_cpu(cpufreq_policy_cpu, cpu) = -1; -- cgit v0.10.2 From 030f19f0e24c020e3577d9a0da878e417efc2b39 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 23 Jul 2013 08:44:34 +0200 Subject: drm/mgag200: Fix logic in mgag200_bo_pin() (v2) Add missing 'return 0;'. v2: Simplified patch as suggested by Dave Airlie Signed-off-by: Egbert Eich Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 3acb2b0..13878d5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -353,6 +353,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) bo->pin_count++; if (gpu_addr) *gpu_addr = mgag200_bo_gpu_offset(bo); + return 0; } mgag200_ttm_placement(bo, pl_flag); -- cgit v0.10.2 From 64c29076646aa0fc094c4b3ea118ea5cb912bfc0 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jul 2013 15:07:22 +0200 Subject: drm/mgag200: Add an crtc_disable callback to the crtc helper funcs Signed-off-by: Egbert Eich Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 251784a..2fe1f64 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1251,6 +1251,24 @@ static void mga_crtc_destroy(struct drm_crtc *crtc) kfree(mga_crtc); } +static void mga_crtc_disable(struct drm_crtc *crtc) +{ + int ret; + DRM_DEBUG_KMS("\n"); + mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + if (crtc->fb) { + struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb); + struct drm_gem_object *obj = mga_fb->obj; + struct mgag200_bo *bo = gem_to_mga_bo(obj); + ret = mgag200_bo_reserve(bo, false); + if (ret) + return; + mgag200_bo_push_sysram(bo); + mgag200_bo_unreserve(bo); + } + crtc->fb = NULL; +} + /* These provide the minimum set of functions required to handle a CRTC */ static const struct drm_crtc_funcs mga_crtc_funcs = { .cursor_set = mga_crtc_cursor_set, @@ -1261,6 +1279,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = { }; static const struct drm_crtc_helper_funcs mga_helper_funcs = { + .disable = mga_crtc_disable, .dpms = mga_crtc_dpms, .mode_fixup = mga_crtc_mode_fixup, .mode_set = mga_crtc_mode_set, -- cgit v0.10.2 From 3d5a1c5e300483df005c81c55792268d4a7bff9f Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jul 2013 15:07:25 +0200 Subject: drm/mgag200: Add sysfs support for connectors Signed-off-by: Egbert Eich Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 2fe1f64..020a623 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1600,6 +1600,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev) drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs); + drm_sysfs_connector_add(connector); + mga_connector->i2c = mgag200_i2c_create(dev); if (!mga_connector->i2c) DRM_ERROR("failed to add ddc bus\n"); -- cgit v0.10.2 From da55839870263563cc70e700a7f58090a860576d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jul 2013 15:07:26 +0200 Subject: drm/mgag200: Fix framebuffer pitch calculation The framebuffer pitch calculation needs to be done differently for bpp == 24 - check xf86-video-mga for reference. Signed-off-by: Egbert Eich Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 020a623..c8983f9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -877,7 +877,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8); if (crtc->fb->bits_per_pixel == 24) - pitch = pitch >> (4 - bppshift); + pitch = (pitch * 3) >> (4 - bppshift); else pitch = pitch >> (4 - bppshift); -- cgit v0.10.2 From de7500eafc96274654201bd585fb85e2814ef9b2 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Wed, 17 Jul 2013 15:07:27 +0200 Subject: drm/mgag200: Fix LUT programming for 16bpp Since there are only 32 (64) distinct color values for each color in 16bpp Matrox hardware expects those in a 'dense' manner, ie in the first 32 (64) entries of the respective color. Signed-off-by: Egbert Eich Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index c8983f9..503a414 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc) struct mga_crtc *mga_crtc = to_mga_crtc(crtc); struct drm_device *dev = crtc->dev; struct mga_device *mdev = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; int i; if (!crtc->enabled) @@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc) WREG8(DAC_INDEX + MGA1064_INDEX, 0); + if (fb && fb->bits_per_pixel == 16) { + int inc = (fb->depth == 15) ? 8 : 4; + u8 r, b; + for (i = 0; i < MGAG200_LUT_SIZE; i += inc) { + if (fb->depth == 16) { + if (i > (MGAG200_LUT_SIZE >> 1)) { + r = b = 0; + } else { + r = mga_crtc->lut_r[i << 1]; + b = mga_crtc->lut_b[i << 1]; + } + } else { + r = mga_crtc->lut_r[i]; + b = mga_crtc->lut_b[i]; + } + /* VGA registers */ + WREG8(DAC_INDEX + MGA1064_COL_PAL, r); + WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]); + WREG8(DAC_INDEX + MGA1064_COL_PAL, b); + } + return; + } for (i = 0; i < MGAG200_LUT_SIZE; i++) { /* VGA registers */ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]); -- cgit v0.10.2 From bfcd92a0ae2996a34b1fd020b3e0951946ae6903 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Fri, 19 Jul 2013 06:27:45 -0400 Subject: drm/nouveau/core: xtensa firmware size needs to be 0x40000 no matter what The current logic is wrong since we send fw->size >> 8 to the card. Rounding the size up by 0x100 and 0x1000 didn't seem to help, the card still hung, so go back to what the blob does -- 0x40000. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c index 0639bc5..5f6ede7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c @@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object) return ret; } - ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0, + if (fw->size > 0x40000) { + nv_warn(xtensa, "firmware %s too large\n", name); + release_firmware(fw); + return -EINVAL; + } + + ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0, &xtensa->gpu_fw); if (ret) { release_firmware(fw); -- cgit v0.10.2 From dedaa8f0e6967edb9127a6643d0259e794196ed2 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 19 Jul 2013 23:59:12 +0200 Subject: drm/nvc0/fb: take lock in nvc0_ram_put() Kernel panic caused by list corruption in ltcg seems to indicate a concurrency issue. Take mutex of pfb like nv50_ram_put() to eliminate concurrency. V2: Separate critical section into separate function, avoid taking the lock twice on NVC0 Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h index 6c974dd..db9d6dd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h @@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *); void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nouveau_fb_tile *); -void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **); +void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *); extern int nv50_fb_memtype[0x80]; #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c index af5aa7e..903baff 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c @@ -27,17 +27,10 @@ #include "priv.h" void -nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem) { struct nouveau_mm_node *this; - struct nouveau_mem *mem; - mem = *pmem; - *pmem = NULL; - if (unlikely(mem == NULL)) - return; - - mutex_lock(&pfb->base.mutex); while (!list_empty(&mem->regions)) { this = list_first_entry(&mem->regions, typeof(*this), rl_entry); @@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) } nouveau_mm_free(&pfb->tags, &mem->tag); +} + +void +nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) +{ + struct nouveau_mem *mem = *pmem; + + *pmem = NULL; + if (unlikely(mem == NULL)) + return; + + mutex_lock(&pfb->base.mutex); + __nv50_ram_put(pfb, mem); mutex_unlock(&pfb->base.mutex); kfree(mem); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c index 9c3634a..cf97c4d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c @@ -33,11 +33,19 @@ void nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem) { struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb); + struct nouveau_mem *mem = *pmem; - if ((*pmem)->tag) - ltcg->tags_free(ltcg, &(*pmem)->tag); + *pmem = NULL; + if (unlikely(mem == NULL)) + return; - nv50_ram_put(pfb, pmem); + mutex_lock(&pfb->base.mutex); + if (mem->tag) + ltcg->tags_free(ltcg, &mem->tag); + __nv50_ram_put(pfb, mem); + mutex_unlock(&pfb->base.mutex); + + kfree(mem); } int -- cgit v0.10.2 From 8ff860564076f99aeb4f6d35dcb6ea008624e64e Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 11 Jul 2013 17:28:03 +0100 Subject: drm/nv50/gpio: post-nv92 cards have 32 interrupt lines Since the original merge of nouveau to upstream kernel, we were assuming that nv90 (and later) cards have 32 lines. Based on mmio traces of the binary driver, as well as PBUS error messages during read/write of the e070/e074 registers, we can conclude that nv92 has only 16 lines whereas nv94 (and later) cards have 32. Reported-and-tested-by: David M. Lloyd Signed-off-by: Emil Velikov Cc: dri-devel@lists.freedesktop.org Cc: Ben Skeggs Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index bf489dc..c4c1d41 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) int i; intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050); - if (nv_device(priv)->chipset >= 0x90) + if (nv_device(priv)->chipset > 0x92) intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070); hi = (intr0 & 0x0000ffff) | (intr1 << 16); @@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev) } nv_wr32(priv, 0xe054, intr0); - if (nv_device(priv)->chipset >= 0x90) + if (nv_device(priv)->chipset > 0x92) nv_wr32(priv, 0xe074, intr1); } @@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int ret; ret = nouveau_gpio_create(parent, engine, oclass, - nv_device(parent)->chipset >= 0x90 ? 32 : 16, + nv_device(parent)->chipset > 0x92 ? 32 : 16, &priv); *pobject = nv_object(priv); if (ret) @@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object) /* disable, and ack any pending gpio interrupts */ nv_wr32(priv, 0xe050, 0x00000000); nv_wr32(priv, 0xe054, 0xffffffff); - if (nv_device(priv)->chipset >= 0x90) { + if (nv_device(priv)->chipset > 0x92) { nv_wr32(priv, 0xe070, 0x00000000); nv_wr32(priv, 0xe074, 0xffffffff); } @@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend) { struct nv50_gpio_priv *priv = (void *)object; nv_wr32(priv, 0xe050, 0x00000000); - if (nv_device(priv)->chipset >= 0x90) + if (nv_device(priv)->chipset > 0x92) nv_wr32(priv, 0xe070, 0x00000000); return nouveau_gpio_fini(&priv->base, suspend); } -- cgit v0.10.2 From 8a258353ed46fa9886bff42e869067336eeb1db6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 23 Jul 2013 15:45:11 +0200 Subject: drm/nouveau: fix null pointer dereference in poll_changed Fixes vgaswitcheroo on a card without display. Signed-off-by: Maarten Lankhorst Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 4c1bc06..8f6d63d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -398,7 +398,8 @@ void nouveau_fbcon_output_poll_changed(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - drm_fb_helper_hotplug_event(&drm->fbcon->helper); + if (drm->fbcon) + drm_fb_helper_hotplug_event(&drm->fbcon->helper); } static int -- cgit v0.10.2 From 921837634de046acd32a7e02157349be4e97885a Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 27 Jul 2013 00:26:59 -0400 Subject: drm/nv50/mc: include vp in the fb error reporting mask Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index 0cb322a..f25fc5f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -41,7 +41,7 @@ nv50_mc_intr[] = { { 0x04000000, NVDEV_ENGINE_DISP }, { 0x10000000, NVDEV_SUBDEV_BUS }, { 0x80000000, NVDEV_ENGINE_SW }, - { 0x0000d101, NVDEV_SUBDEV_FB }, + { 0x0002d101, NVDEV_SUBDEV_FB }, {}, }; -- cgit v0.10.2 From 18f35fa6584fb28c674014674de20ed82bb84618 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 27 Jul 2013 00:27:01 -0400 Subject: drm/nv31/mpeg: fix mpeg engine initialization object->engine is null, which leads to a null deref down the line Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index 49ecbb8..9f7c7d5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int nv31_mpeg_init(struct nouveau_object *object) { - struct nouveau_engine *engine = nv_engine(object->engine); - struct nv31_mpeg_priv *priv = (void *)engine; + struct nouveau_engine *engine = nv_engine(object); + struct nv31_mpeg_priv *priv = (void *)object; struct nouveau_fb *pfb = nouveau_fb(object); int ret, i; -- cgit v0.10.2 From 02d69294a174d7cb6a76080b6d16971ca08728d4 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sun, 28 Jul 2013 22:30:57 -0400 Subject: drm/nva3-/disp: fix hda eld writing, needs to be padded Commits 0a9e2b959 (drm/nvd0/disp: move HDA codec setup to core) and a4feaf4ea (drm/nva3/disp: move hda codec handling to core) moved code around but neglected to fill data up to 0x60 as before. This caused /proc/asound/cardN/eld#3.0 to show eld_valid as 0. With this patch, that file is again populated with the correct data. See https://bugs.freedesktop.org/show_bug.cgi?id=67051 Reported-and-tested-by: Alex Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c index 373dbcc..a19e7d7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c @@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) if (data && data[0]) { for (i = 0; i < size; i++) nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]); + for (; i < 0x60; i++) + nv_wr32(priv, 0x61c440 + soff, (i << 8)); nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003); } else if (data) { diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c index dc57e24..7176393 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c @@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size) if (data && data[0]) { for (i = 0; i < size; i++) nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]); + for (; i < 0x60; i++) + nv_wr32(priv, 0x10ec00 + soff, (i << 8)); nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003); } else if (data) { -- cgit v0.10.2 From 9a7046d55f319b2dde5d2536cc2adb01ebdbe09e Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Sun, 28 Jul 2013 21:00:23 +0100 Subject: drm/nv50-/disp: remove dcb_outp_match call, and related variables Unused and irrelavant since the code move of DP training/linkcontrol interrupt Signed-off-by: Emil Velikov Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c index ab1e918..526b752 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c @@ -47,14 +47,8 @@ int nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) { struct nv50_disp_priv *priv = (void *)object->engine; - struct nouveau_bios *bios = nouveau_bios(priv); - const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12; const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3; - const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2; const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); - const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or); - struct dcb_output outp; - u8 ver, hdr; u32 data; int ret = -EINVAL; @@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) return -EINVAL; data = *(u32 *)args; - if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp)) - return -ENODEV; switch (mthd & ~0x3f) { case NV50_DISP_SOR_PWR: -- cgit v0.10.2 From 35095f7529bb6abdfc956e7a41ca6957520b70a7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Sat, 27 Jul 2013 10:17:12 +0200 Subject: drm/nouveau: fix size check for cards without vm Op 24-07-13 17:55, Dan Carpenter schreef: > Hello Maarten Lankhorst, > > This is a semi-automatic email about new static checker warnings. > > The patch 0108bc808107: "drm/nouveau: do not allow negative sizes for > now" from Jul 7, 2013, leads to the following Smatch complaint: > > drivers/gpu/drm/nouveau/nouveau_bo.c:222 nouveau_bo_new() > warn: variable dereferenced before check 'drm->client.base.vm' (see line 201) > > drivers/gpu/drm/nouveau/nouveau_bo.c > 200 int type = ttm_bo_type_device; > 201 int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1); > ^^^^^^^^^^^^^^^^^^^ > New dereference. > > 202 > 203 if (size <= 0 || size > max_size) { > 204 nv_warn(drm, "skipped size %x\n", (u32)size); > 205 return -EINVAL; > 206 } > 207 > 208 if (sg) > 209 type = ttm_bo_type_sg; > 210 > 211 nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); > 212 if (!nvbo) > 213 return -ENOMEM; > 214 INIT_LIST_HEAD(&nvbo->head); > 215 INIT_LIST_HEAD(&nvbo->entry); > 216 INIT_LIST_HEAD(&nvbo->vma_list); > 217 nvbo->tile_mode = tile_mode; > 218 nvbo->tile_flags = tile_flags; > 219 nvbo->bo.bdev = &drm->ttm.bdev; > 220 > 221 nvbo->page_shift = 12; > 222 if (drm->client.base.vm) { > ^^^^^^^^^^^^^^^^^^^ > Old check. > > 223 if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024) > 224 nvbo->page_shift = drm->client.base.vm->vmm->lpg_shift; > > regards, > dan carpenter 8<----- Commit 0108bc808107: "drm/nouveau: do not allow negative sizes for now" broke older nvidia gpu's that lack a vm. Add an explicit check to handle this. Reported-by: Dan Carpenter Reported-by: konrad wilk Signed-off-by: Maarten Lankhorst Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4e7ee5f..af20fba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, size_t acc_size; int ret; int type = ttm_bo_type_device; - int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1); + int lpg_shift = 12; + int max_size; + + if (drm->client.base.vm) + lpg_shift = drm->client.base.vm->vmm->lpg_shift; + max_size = INT_MAX & ~((1 << lpg_shift) - 1); if (size <= 0 || size > max_size) { nv_warn(drm, "skipped size %x\n", (u32)size); -- cgit v0.10.2 From 3d8b2b489e490ae63b7eddb3dcdfcee9bc32d473 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 29 Jul 2013 19:05:17 -0400 Subject: drm/nv40/mpeg: write magic value to channel object to make it work Looks like the rewrite in commit ebb945a94b ("drm/nouveau: port all engines to new engine module format") missed that one little detail. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c index f7c581a..dd61960 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent, if (ret) return ret; + nv_wo32(&chan->base.base, 0x78, 0x02001ec1); return 0; } -- cgit v0.10.2 From dc409df9447a4e3884d150e2b0dbd89242403fa6 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 29 Jul 2013 19:05:18 -0400 Subject: drm/nv31/mpeg: don't recognize nv3x cards as having nv44 graph class Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c index 9f7c7d5..c190043 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c @@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object) /* PMPEG init */ nv_wr32(priv, 0x00b32c, 0x00000000); nv_wr32(priv, 0x00b314, 0x00000100); - nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031); + if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv)) + nv_wr32(priv, 0x00b220, 0x00000044); + else + nv_wr32(priv, 0x00b220, 0x00000031); nv_wr32(priv, 0x00b300, 0x02001ec1); nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); -- cgit v0.10.2 From e0bacd2f7e0abf7fd26ab7d12e1cfb96a5350fad Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 30 Jul 2013 11:47:47 +1000 Subject: drm/nouveau/vm: make vm refcount into a kref Never used to be required, but a recent change made it necessary. Reported-by: Maarten Lankhorst Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h index f2e87b1..fcf57fa 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h @@ -55,7 +55,7 @@ struct nouveau_vma { struct nouveau_vm { struct nouveau_vmmgr *vmm; struct nouveau_mm mm; - int refcount; + struct kref refcount; struct list_head pgd_list; atomic_t engref[NVDEV_SUBDEV_NR]; diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c index 67fcb6c..ef3133e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c @@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, INIT_LIST_HEAD(&vm->pgd_list); vm->vmm = vmm; - vm->refcount = 1; + kref_init(&vm->refcount); vm->fpde = offset >> (vmm->pgt_bits + 12); vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12); @@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) } static void -nouveau_vm_del(struct nouveau_vm *vm) +nouveau_vm_del(struct kref *kref) { + struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount); struct nouveau_vm_pgd *vpgd, *tmp; list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { @@ -458,27 +459,19 @@ int nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, struct nouveau_gpuobj *pgd) { - struct nouveau_vm *vm; - int ret; - - vm = ref; - if (vm) { - ret = nouveau_vm_link(vm, pgd); + if (ref) { + int ret = nouveau_vm_link(ref, pgd); if (ret) return ret; - vm->refcount++; + kref_get(&ref->refcount); } - vm = *ptr; - *ptr = ref; - - if (vm) { - nouveau_vm_unlink(vm, pgd); - - if (--vm->refcount == 0) - nouveau_vm_del(vm); + if (*ptr) { + nouveau_vm_unlink(*ptr, pgd); + kref_put(&(*ptr)->refcount, nouveau_vm_del); } + *ptr = ref; return 0; } -- cgit v0.10.2 From 7a7da592cbb22a1d360638dbecc393470c5effe3 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 23 Jul 2013 15:49:39 +0200 Subject: drm/nouveau: fix semaphore dmabuf obj Fixes some dmabuf object errors on nv50 chipset and below. Cc: stable@vger.kernel.org [3.7+] Signed-off-by: Maarten Lankhorst Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c index 8e47a9b..22aa996 100644 --- a/drivers/gpu/drm/nouveau/nv17_fence.c +++ b/drivers/gpu/drm/nouveau/nv17_fence.c @@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct nouveau_object *object; u32 start = mem->start * PAGE_SIZE; - u32 limit = mem->start + mem->size - 1; + u32 limit = start + mem->size - 1; int ret = 0; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index f9701e5..0ee3638 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan) struct nv10_fence_chan *fctx; struct ttm_mem_reg *mem = &priv->bo->bo.mem; struct nouveau_object *object; + u32 start = mem->start * PAGE_SIZE; + u32 limit = start + mem->size - 1; int ret, i; fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL); @@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan) fctx->base.sync = nv17_fence_sync; ret = nouveau_object_new(nv_object(chan->cli), chan->handle, - NvSema, 0x0002, + NvSema, 0x003d, &(struct nv_dma_class) { .flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR, - .start = mem->start * PAGE_SIZE, - .limit = mem->size - 1, + .start = start, + .limit = limit, }, sizeof(struct nv_dma_class), &object); /* dma objects for display sync channel semaphore blocks */ for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) { struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i); + u32 start = bo->bo.mem.start * PAGE_SIZE; + u32 limit = start + bo->bo.mem.size - 1; ret = nouveau_object_new(nv_object(chan->cli), chan->handle, NvEvoSema0 + i, 0x003d, &(struct nv_dma_class) { .flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR, - .start = bo->bo.offset, - .limit = bo->bo.offset + 0xfff, + .start = start, + .limit = limit, }, sizeof(struct nv_dma_class), &object); } -- cgit v0.10.2 From a0db856a95a29efb1c23db55c02d9f0ff4f0db48 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 30 Jul 2013 00:16:21 -0700 Subject: net_sched: Fix stack info leak in cbq_dump_wrr(). Make sure the reserved fields, and padding (if any), are fully initialized. Based upon a patch by Dan Carpenter and feedback from Joe Perches. Signed-off-by: David S. Miller diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 71a5688..7a42c81 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1465,6 +1465,7 @@ static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl) unsigned char *b = skb_tail_pointer(skb); struct tc_cbq_wrropt opt; + memset(&opt, 0, sizeof(opt)); opt.flags = 0; opt.allot = cl->allot; opt.priority = cl->priority + 1; -- cgit v0.10.2 From 610d80eaa987e7b1a2d07ee800c9722e227a3b47 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 30 Jul 2013 13:34:09 +0200 Subject: ASoC: bf5xx-ac97: Fix compile error with SND_BF5XX_HAVE_COLD_RESET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_SND_BF5XX_HAVE_COLD_RESET is enabled building the blackfin ac97 driver fails with the following compile error: sound/soc/blackfin/bf5xx-ac97.c: In function ‘asoc_bfin_ac97_probe’: sound/soc/blackfin/bf5xx-ac97.c:297: error: expected ‘;’ before ‘{’ token sound/soc/blackfin/bf5xx-ac97.c:302: error: label ‘gpio_err’ used but not defined The issue was introduced in commit 6dab2fd7 ("ASoC: bf5xx-ac97: Convert to devm_gpio_request_one()"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index efb1dae..e82eb37 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -294,11 +294,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev) /* Request PB3 as reset pin */ ret = devm_gpio_request_one(&pdev->dev, CONFIG_SND_BF5XX_RESET_GPIO_NUM, - GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") { + GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET"); + if (ret) { dev_err(&pdev->dev, "Failed to request GPIO_%d for reset: %d\n", CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret); - goto gpio_err; + return ret; } #endif -- cgit v0.10.2 From 016d5baad04269e8559332df05f89bd95b52d6ad Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 30 Jul 2013 14:00:42 +0200 Subject: ACPI / battery: Fix parsing _BIX return value The _BIX method returns extended battery info as a package. According the ACPI spec (ACPI 5, Section 10.2.2.2), the first member of that package should be "Revision". However, the current ACPI battery driver treats the first member as "Power Unit" which should be the second member. This causes the result of _BIX return data parsing to be incorrect. Fix this by adding a new member called 'revision' to struct acpi_battery and adding the offsetof() information on it to extended_info_offsets[] as the first row. [rjw: Changelog] Reported-and-tested-by: Jan Hoffmann References: http://bugzilla.kernel.org/show_bug.cgi?id=60519 Signed-off-by: Lan Tianyu Cc: 2.6.34+ Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 082b4dd..d405fba 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -117,6 +117,7 @@ struct acpi_battery { struct acpi_device *device; struct notifier_block pm_nb; unsigned long update_time; + int revision; int rate_now; int capacity_now; int voltage_now; @@ -359,6 +360,7 @@ static struct acpi_offsets info_offsets[] = { }; static struct acpi_offsets extended_info_offsets[] = { + {offsetof(struct acpi_battery, revision), 0}, {offsetof(struct acpi_battery, power_unit), 0}, {offsetof(struct acpi_battery, design_capacity), 0}, {offsetof(struct acpi_battery, full_charge_capacity), 0}, -- cgit v0.10.2 From 2b44c4db2e2f1765d35163a861d301038e0c8a75 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 24 Jul 2013 17:41:33 -0700 Subject: freezer: set PF_SUSPEND_TASK flag on tasks that call freeze_processes Calling freeze_processes sets a global flag that will cause any process that calls try_to_freeze to enter the refrigerator. It skips sending a signal to the current task, but if the current task ever hits try_to_freeze, all threads will be frozen and the system will deadlock. Set a new flag, PF_SUSPEND_TASK, on the task that calls freeze_processes. The flag notifies the freezer that the thread is involved in suspend and should not be frozen. Also add a WARN_ON in thaw_processes if the caller does not have the PF_SUSPEND_TASK flag set to catch if a different task calls thaw_processes than the one that called freeze_processes, leaving a task with PF_SUSPEND_TASK permanently set on it. Threads that spawn off a task with PF_SUSPEND_TASK set (which swsusp does) will also have PF_SUSPEND_TASK set, preventing them from freezing while they are helping with suspend, but they need to be dead by the time suspend is triggered, otherwise they may run when userspace is expected to be frozen. Add a WARN_ON in thaw_processes if more than one thread has the PF_SUSPEND_TASK flag set. Reported-and-tested-by: Michael Leun Signed-off-by: Colin Cross Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/sched.h b/include/linux/sched.h index 50d04b9..d722490 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1628,6 +1628,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ +#define PF_SUSPEND_TASK 0x80000000 /* this thread called freeze_processes and should not be frozen */ /* * Only the _current_ task can read/write to tsk->flags, but other diff --git a/kernel/freezer.c b/kernel/freezer.c index 8b2afc1..b462fa1 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -33,7 +33,7 @@ static DEFINE_SPINLOCK(freezer_lock); */ bool freezing_slow_path(struct task_struct *p) { - if (p->flags & PF_NOFREEZE) + if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) return false; if (pm_nosig_freezing || cgroup_freezing(p)) diff --git a/kernel/power/process.c b/kernel/power/process.c index fc0df84..06ec886 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -109,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only) /** * freeze_processes - Signal user space processes to enter the refrigerator. + * The current thread will not be frozen. The same process that calls + * freeze_processes must later call thaw_processes. * * On success, returns 0. On failure, -errno and system is fully thawed. */ @@ -120,6 +122,9 @@ int freeze_processes(void) if (error) return error; + /* Make sure this task doesn't get frozen */ + current->flags |= PF_SUSPEND_TASK; + if (!pm_freezing) atomic_inc(&system_freezing_cnt); @@ -168,6 +173,7 @@ int freeze_kernel_threads(void) void thaw_processes(void) { struct task_struct *g, *p; + struct task_struct *curr = current; if (pm_freezing) atomic_dec(&system_freezing_cnt); @@ -182,10 +188,15 @@ void thaw_processes(void) read_lock(&tasklist_lock); do_each_thread(g, p) { + /* No other threads should have PF_SUSPEND_TASK set */ + WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK)); __thaw_task(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); + WARN_ON(!(curr->flags & PF_SUSPEND_TASK)); + curr->flags &= ~PF_SUSPEND_TASK; + usermodehelper_enable(); schedule(); -- cgit v0.10.2 From 179fbd5a45f0d4034cc6fd37b8d367a3b79663c4 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 19 Jul 2013 15:51:58 +0100 Subject: xen/evtchn: avoid a deadlock when unbinding an event channel Unbinding an event channel (either with the ioctl or when the evtchn device is closed) may deadlock because disable_irq() is called with port_user_lock held which is also locked by the interrupt handler. Think of the IOCTL_EVTCHN_UNBIND is being serviced, the routine has just taken the lock, and an interrupt happens. The evtchn_interrupt is invoked, tries to take the lock and spins forever. A quick glance at the code shows that the spinlock is a local IRQ variant. Unfortunately that does not help as "disable_irq() waits for the interrupt handler on all CPUs to stop running. If the irq occurs on another VCPU, it tries to take port_user_lock and can't because the unbind ioctl is holding it." (from David). Hence we cannot depend on the said spinlock to protect us. We could make it a system wide IRQ disable spinlock but there is a better way. We can piggyback on the fact that the existence of the spinlock is to make get_port_user() checks be up-to-date. And we can alter those checks to not depend on the spin lock (as it's protected by u->bind_mutex in the ioctl) and can remove the unnecessary locking (this is IOCTL_EVTCHN_UNBIND) path. In the interrupt handler we cannot use the mutex, but we do not need it. "The unbind disables the irq before making the port user stale, so when you clear it you are guaranteed that the interrupt handler that might use that port cannot be running." (from David). Hence this patch removes the spinlock usage on the teardown path and piggybacks on disable_irq happening before we muck with the get_port_user() data. This ensures that the interrupt handler will never run on stale data. Signed-off-by: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk [v1: Expanded the commit description a bit] diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index 8feecf0..b6165e0 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file, if (unbind.port >= NR_EVENT_CHANNELS) break; - spin_lock_irq(&port_user_lock); - rc = -ENOTCONN; - if (get_port_user(unbind.port) != u) { - spin_unlock_irq(&port_user_lock); + if (get_port_user(unbind.port) != u) break; - } disable_irq(irq_from_evtchn(unbind.port)); - spin_unlock_irq(&port_user_lock); - evtchn_unbind_from_user(u, unbind.port); rc = 0; @@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp) int i; struct per_user_data *u = filp->private_data; - spin_lock_irq(&port_user_lock); - - free_page((unsigned long)u->ring); - for (i = 0; i < NR_EVENT_CHANNELS; i++) { if (get_port_user(i) != u) continue; disable_irq(irq_from_evtchn(i)); - } - - spin_unlock_irq(&port_user_lock); - - for (i = 0; i < NR_EVENT_CHANNELS; i++) { - if (get_port_user(i) != u) - continue; - evtchn_unbind_from_user(get_port_user(i), i); } + free_page((unsigned long)u->ring); kfree(u->name); kfree(u); -- cgit v0.10.2 From 7ad18dd03c426b017df12a45a56e5b36d5976afb Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Wed, 3 Jul 2013 17:28:22 +0000 Subject: MIPS: Fix multiple definitions of UNCAC_BASE. Fix build error below: arch/mips/include/asm/mach-generic/spaces.h:29:0: warning: "UNCAC_BASE" redefined [enabled by default] In file included from arch/mips/include/asm/addrspace.h:13:0, from arch/mips/include/asm/barrier.h:11, from arch/mips/include/asm/bitops.h:18, from include/linux/bitops.h:22, from include/linux/kernel.h:10, from include/asm-generic/bug.h:13, from arch/mips/include/asm/bug.h:41, from include/linux/bug.h:4, from include/linux/page-flags.h:9, from kernel/bounds.c:9: arch/mips/include/asm/mach-ar7/spaces.h:20:0: note: this is the location of the previous definition Signed-off-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5583/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h index 5b2f2e6..9488fa5 100644 --- a/arch/mips/include/asm/mach-generic/spaces.h +++ b/arch/mips/include/asm/mach-generic/spaces.h @@ -25,8 +25,12 @@ #else #define CAC_BASE _AC(0x80000000, UL) #endif +#ifndef IO_BASE #define IO_BASE _AC(0xa0000000, UL) +#endif +#ifndef UNCAC_BASE #define UNCAC_BASE _AC(0xa0000000, UL) +#endif #ifndef MAP_BASE #ifdef CONFIG_KVM_GUEST -- cgit v0.10.2 From 1d3e2d79a7d5ab56b382ea96b64c4daa9d6f0ce4 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sun, 28 Jul 2013 21:20:25 +0100 Subject: MIPS: uapi/asm/siginfo.h: Fix GCC 4.1.2 compilation It wasn't until GCC 4.3 I believe that the __SIZEOF_*__ predefined macros were added. The change below switches to the _MIPS_SZLONG macro so that compilation with e.g. GCC 4.1.2 succeeds. This is a user API header so I think this is even more important, for older userland support. The change adds an unsuccessful default too, to catch any compiler configuration oddities. Signed-off-by: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5630/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h index b7a2306..88e292b 100644 --- a/arch/mips/include/uapi/asm/siginfo.h +++ b/arch/mips/include/uapi/asm/siginfo.h @@ -25,11 +25,12 @@ struct siginfo; /* * Careful to keep union _sifields from shifting ... */ -#if __SIZEOF_LONG__ == 4 +#if _MIPS_SZLONG == 32 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) -#endif -#if __SIZEOF_LONG__ == 8 +#elif _MIPS_SZLONG == 64 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) +#else +#error _MIPS_SZLONG neither 32 nor 64 #endif #include -- cgit v0.10.2 From 314878d246955e0c6fff95d8ae64285fe828c785 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 23 Jul 2013 15:40:37 +0100 Subject: MIPS: Set default CPU type for BCM47XX platforms If neither BCM47XX_SSD nor BCM47XX_BCMA is selected, then no CPU type is available leading to build problems. We fix this problem by using MIPS32r1 as the default CPU type for the BCM47XX platform. Signed-off-by: Markos Chandras Acked-by: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5618/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index c3abed3..e12764c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -114,6 +114,7 @@ config BCM47XX select FW_CFE select HW_HAS_PCI select IRQ_CPU + select SYS_HAS_CPU_MIPS32_R1 select NO_EXCEPT_FILL select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN diff --git a/arch/mips/bcm47xx/Kconfig b/arch/mips/bcm47xx/Kconfig index ba61192..2b8b118 100644 --- a/arch/mips/bcm47xx/Kconfig +++ b/arch/mips/bcm47xx/Kconfig @@ -2,7 +2,6 @@ if BCM47XX config BCM47XX_SSB bool "SSB Support for Broadcom BCM47XX" - select SYS_HAS_CPU_MIPS32_R1 select SSB select SSB_DRIVER_MIPS select SSB_DRIVER_EXTIF -- cgit v0.10.2 From c055629b279d68c79b8776681c17a2234fecf8af Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 25 Jul 2013 16:11:28 +0100 Subject: MIPS: powertv: Fix arguments for free_reserved_area() Commit 6e7582bf35b8a5a330fd08b398ae445bac86917a "MIPS: PowerTV: use free_reserved_area() to simplify code" merged in 3.11-rc1, broke the build for the powertv defconfig with the following build error: arch/mips/powertv/asic/asic_devices.c: In function 'platform_release_memory': arch/mips/powertv/asic/asic_devices.c:533:7: error: passing argument 1 of 'free_reserved_area' makes pointer from integer without a cast [-Werror] The free_reserved_area() function expects a void * pointer for the start address and a void * pointer for the end one. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/5624/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index 9f64c23..0238af1 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c @@ -529,8 +529,7 @@ EXPORT_SYMBOL(asic_resource_get); */ void platform_release_memory(void *ptr, int size) { - free_reserved_area((unsigned long)ptr, (unsigned long)(ptr + size), - -1, NULL); + free_reserved_area(ptr, ptr + size, -1, NULL); } EXPORT_SYMBOL(platform_release_memory); -- cgit v0.10.2 From c4091d3fbbed922a3641e5e749655e49cc0d4dee Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 24 Jul 2013 17:12:10 +0100 Subject: MIPS: BMIPS: do not change interrupt routing depending on boot CPU Commit 4df715aa ("MIPS: BMIPS: support booting from physical CPU other than 0") changed the interupt routing when we are booting from physical CPU 0, but the settings are actually correct if we are booting from physical CPU 0 or CPU 1. Revert that specific change. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: jogo@openwrt.org Cc: blogic@openwrt.org Patchwork: https://patchwork.linux-mips.org/patch/5622/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index c0bb4d5..89417c9 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -79,15 +79,9 @@ static void __init bmips_smp_setup(void) * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output - * - * If booting from TP1, leave the existing CMT interrupt routing - * such that TP0 responds to SW1 and TP1 responds to SW0. */ - if (boot_cpu == 0) - change_c0_brcm_cmt_intr(0xf8018000, + change_c0_brcm_cmt_intr(0xf8018000, (0x02 << 27) | (0x03 << 15)); - else - change_c0_brcm_cmt_intr(0xf8018000, (0x1d << 27)); /* single core, 2 threads (2 pipelines) */ max_cpus = 2; -- cgit v0.10.2 From ff5fadaff39180dc0b652753b5614a564711be29 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 24 Jul 2013 17:12:11 +0100 Subject: MIPS: BMIPS: fix slave CPU booting when physical CPU is not 0 The current BMIPS SMP code assumes that the slave CPU is physical and logical CPU 1, but on some systems such as BCM3368, the slave CPU is physical CPU0. Fix the code to read the physical CPU (thread ID) we are running this code on, and adjust the relocation vector address based on it. This allows bringing up the second CPU on BCM3368 for instance. Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: jogo@openwrt.org Cc: blogic@openwrt.org Patchwork: https://patchwork.linux-mips.org/patch/5621/ Signed-off-by: Ralf Baechle diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index f739aed..bd79c4f 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -54,7 +54,11 @@ LEAF(bmips_smp_movevec) /* set up CPU1 CBR; move BASE to 0xa000_0000 */ li k0, 0xff400000 mtc0 k0, $22, 6 - li k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1 + /* set up relocation vector address based on thread ID */ + mfc0 k1, $22, 3 + srl k1, 16 + andi k1, 0x8000 + or k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_0 or k0, k1 li k1, 0xa0080000 sw k1, 0(k0) diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 89417c9..159abc8 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -196,9 +196,15 @@ static void bmips_init_secondary(void) #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380) void __iomem *cbr = BMIPS_GET_CBR(); unsigned long old_vec; + unsigned long relo_vector; + int boot_cpu; - old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1); - __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1); + boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31)); + relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 : + BMIPS_RELO_VECTOR_CONTROL_1; + + old_vec = __raw_readl(cbr + relo_vector); + __raw_writel(old_vec & ~0x20000000, cbr + relo_vector); clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0); #elif defined(CONFIG_CPU_BMIPS5000) -- cgit v0.10.2 From ae1fe07f3f422c62a0baf6a777141d7110e8a111 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jul 2013 19:48:32 +0300 Subject: RDMA/cxgb4: Fix stack info leak in c4iw_create_qp() "uresp.ma_sync_key" doesn't get set on this path so we leak 8 bytes of data. Signed-off-by: Dan Carpenter Acked-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 2320404..a4975e1 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1657,6 +1657,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, if (mm5) { uresp.ma_sync_key = ucontext->key; ucontext->key += PAGE_SIZE; + } else { + uresp.ma_sync_key = 0; } uresp.sq_key = ucontext->key; ucontext->key += PAGE_SIZE; -- cgit v0.10.2 From 63ea37495714849a5a7986244d9d656e0af14961 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 29 Jul 2013 22:34:29 +0300 Subject: RDMA/ocrdma: Fix several stack info leaks A grab bag of places which don't properly initialize stack data. I removed one place which cleared ".rsvd" because it's not needed now that I have added a memset() earlier in the function. Signed-off-by: Dan Carpenter Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index dcfbab1..f36630e 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -242,6 +242,7 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev, memset(ctx->ah_tbl.va, 0, map_len); ctx->ah_tbl.len = map_len; + memset(&resp, 0, sizeof(resp)); resp.ah_tbl_len = ctx->ah_tbl.len; resp.ah_tbl_page = ctx->ah_tbl.pa; @@ -253,7 +254,6 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev, resp.wqe_size = dev->attr.wqe_size; resp.rqe_size = dev->attr.rqe_size; resp.dpp_wqe_size = dev->attr.wqe_size; - resp.rsvd = 0; memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver)); status = ib_copy_to_udata(udata, &resp, sizeof(resp)); @@ -338,6 +338,7 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd, struct ocrdma_alloc_pd_uresp rsp; struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx); + memset(&rsp, 0, sizeof(rsp)); rsp.id = pd->id; rsp.dpp_enabled = pd->dpp_enabled; db_page_addr = pd->dev->nic_info.unmapped_db + @@ -692,6 +693,7 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata, struct ocrdma_ucontext *uctx; struct ocrdma_create_cq_uresp uresp; + memset(&uresp, 0, sizeof(uresp)); uresp.cq_id = cq->id; uresp.page_size = cq->len; uresp.num_pages = 1; @@ -1460,6 +1462,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata) int status; struct ocrdma_create_srq_uresp uresp; + memset(&uresp, 0, sizeof(uresp)); uresp.rq_dbid = srq->rq.dbid; uresp.num_rq_pages = 1; uresp.rq_page_addr[0] = srq->rq.pa; -- cgit v0.10.2 From 604296303f5f2698e4682c8aefb413554bc4b12a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jul 2013 20:04:59 +0300 Subject: RDMA/nes: Fix info leaks in nes_create_qp() and nes_create_cq() We pass a few bytes of uninitialized stack memory to the user here. Signed-off-by: Dan Carpenter Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 8f67fe2..5b53ca5 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1384,6 +1384,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, if (ibpd->uobject) { uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index; + uresp.mmap_rq_db_index = 0; uresp.actual_sq_size = sq_size; uresp.actual_rq_size = rq_size; uresp.qp_id = nesqp->hwqp.qp_id; @@ -1767,7 +1768,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries, resp.cq_id = nescq->hw_cq.cq_number; resp.cq_size = nescq->hw_cq.cq_size; resp.mmap_db_index = 0; - if (ib_copy_to_udata(udata, &resp, sizeof resp)) { + if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) { nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num); kfree(nescq); return ERR_PTR(-EFAULT); -- cgit v0.10.2 From 246fcdbc9d6c7ee1b12e299427efbc2ab49e40b5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 29 Jul 2013 22:19:14 +0300 Subject: RDMA/cxgb3: Fix stack info leak in iwch_create_cq() The "uresp.reserved" field isn't initialized on this path so it could leak uninitialized stack information to the user. Signed-off-by: Dan Carpenter Acked-by: Steve Wise Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index e87f220..d228383 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -226,6 +226,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) * sizeof(struct t3_cqe)); uresp.memsize = mm->len; + uresp.reserved = 0; resplen = sizeof uresp; } if (ib_copy_to_udata(udata, &uresp, resplen)) { -- cgit v0.10.2 From b268e4db3d04ed83ecc76b0454b12a8884445f88 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 12 Jul 2013 09:24:56 -0400 Subject: IB/qib: Add err_decode() call for ring dump Commit 0b3ddf380ca7 ("Log all SDMA errors unconditionally") missed part of the patch. This also corrects a format warning when dma_addr_t is 32 bits on a 64 bit system. Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 21e8b09..016e742 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -1596,6 +1596,8 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs) struct qib_devdata *dd = ppd->dd; errs &= QIB_E_P_SDMAERRS; + err_decode(ppd->cpspec->sdmamsgbuf, sizeof(ppd->cpspec->sdmamsgbuf), + errs, qib_7322p_error_msgs); if (errs & QIB_E_P_SDMAUNEXPDATA) qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit, diff --git a/drivers/infiniband/hw/qib/qib_sdma.c b/drivers/infiniband/hw/qib/qib_sdma.c index 32162d3..9b5322d 100644 --- a/drivers/infiniband/hw/qib/qib_sdma.c +++ b/drivers/infiniband/hw/qib/qib_sdma.c @@ -717,7 +717,7 @@ void dump_sdma_state(struct qib_pportdata *ppd) struct qib_sdma_txreq *txp, *txpnext; __le64 *descqp; u64 desc[2]; - dma_addr_t addr; + u64 addr; u16 gen, dwlen, dwoffset; u16 head, tail, cnt; -- cgit v0.10.2 From 741ddbcfd26f192b0677961385b599aa785f8119 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 23 Jul 2013 17:46:58 +0100 Subject: xen/tmem: do not allow XEN_TMEM on ARM64 tmem is not supported on arm or arm64 yet. Will revert this once the Xen hypervisor supports it. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 9e02d60..23eae5c 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -145,7 +145,7 @@ config SWIOTLB_XEN config XEN_TMEM tristate - depends on !ARM + depends on !ARM && !ARM64 default m if (CLEANCACHE || FRONTSWAP) help Shim to interface in-kernel Transcendent Memory hooks -- cgit v0.10.2 From 42a21826dc54583cdb79cc8477732e911ac9c376 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jul 2013 00:22:53 -0400 Subject: drm/radeon/atom: initialize more atom interpretor elements to 0 The ProcessAuxChannel table on some rv635 boards assumes the divmul members are initialized to 0 otherwise we get an invalid fb offset since it has a bad mask set when setting the fb base. While here initialize all the atom interpretor elements to 0. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=60639 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index fb441a7..15da7ef 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1222,12 +1222,17 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params) int r; mutex_lock(&ctx->mutex); + /* reset data block */ + ctx->data_block = 0; /* reset reg block */ ctx->reg_block = 0; /* reset fb window */ ctx->fb_base = 0; /* reset io mode */ ctx->io_mode = ATOM_IO_MM; + /* reset divmul */ + ctx->divmul[0] = 0; + ctx->divmul[1] = 0; r = atom_execute_table_locked(ctx, index, params); mutex_unlock(&ctx->mutex); return r; -- cgit v0.10.2 From a838834b2f7cbc09b6319a1fc332c03e4d665b20 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jul 2013 16:43:55 -0400 Subject: drm: fix 64 bit drm fixed point helpers Sign bit wasn't handled properly and a small typo. Thanks to Christian for helping me sort this out. Signed-off-by: Alex Deucher diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index f5e1168..d639049 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h @@ -84,12 +84,12 @@ static inline int drm_fixp2int(int64_t a) return ((s64)a) >> DRM_FIXED_POINT; } -static inline s64 drm_fixp_msbset(int64_t a) +static inline unsigned drm_fixp_msbset(int64_t a) { unsigned shift, sign = (a >> 63) & 1; for (shift = 62; shift > 0; --shift) - if ((a >> shift) != sign) + if (((a >> shift) & 1) != sign) return shift; return 0; @@ -100,9 +100,9 @@ static inline s64 drm_fixp_mul(s64 a, s64 b) unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b); s64 result; - if (shift > 63) { - shift = shift - 63; - a >>= shift >> 1; + if (shift > 61) { + shift = shift - 61; + a >>= (shift >> 1) + (shift & 1); b >>= shift >> 1; } else shift = 0; @@ -120,7 +120,7 @@ static inline s64 drm_fixp_mul(s64 a, s64 b) static inline s64 drm_fixp_div(s64 a, s64 b) { - unsigned shift = 63 - drm_fixp_msbset(a); + unsigned shift = 62 - drm_fixp_msbset(a); s64 result; a <<= shift; @@ -154,7 +154,7 @@ static inline s64 drm_fixp_exp(s64 x) } if (x < 0) - sum = drm_fixp_div(1, sum); + sum = drm_fixp_div(DRM_FIXED_ONE, sum); return sum; } -- cgit v0.10.2 From 31f731af513bb9925d0a29dba34bb4f71141bf91 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jul 2013 16:56:52 -0400 Subject: drm/radeon/dpm: fix calculations in si_calculate_leakage_for_v_and_t_formula Need to make some slight adjustments for the fixed point math to work properly. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 1604a87..cfb4448 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1765,8 +1765,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe { s64 kt, kv, leakage_w, i_leakage, vddc; s64 temperature, t_slope, t_intercept, av, bv, t_ref; + s64 tmp; - i_leakage = drm_int2fixp(ileakage / 100); + i_leakage = drm_int2fixp(ileakage) / 100; vddc = div64_s64(drm_int2fixp(v), 1000); temperature = div64_s64(drm_int2fixp(t), 1000); @@ -1776,8 +1777,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe bv = div64_s64(drm_int2fixp(coeff->bv), 100000000); t_ref = drm_int2fixp(coeff->t_ref); - kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)), - drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref))); + tmp = drm_fixp_mul(t_slope, vddc) + t_intercept; + kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature)); + kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref))); kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc))); leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc); -- cgit v0.10.2 From 5a344dda944b4eea5a95e47a49ae5b53ce4f49b6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 30 Jul 2013 17:02:29 -0400 Subject: drm/radeon/dpm: re-enable cac control on SI Now that the fixed point functions are fixed we can re-enable cac support. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index cfb4448..7ad22e8 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2044,8 +2044,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev) ni_pi->enable_sq_ramping = false; si_pi->enable_dte = false; - /* XXX: fix me */ - if (0/*si_pi->powertune_data->enable_powertune_by_default*/) { + if (si_pi->powertune_data->enable_powertune_by_default) { ni_pi->enable_power_containment= true; ni_pi->enable_cac = true; if (si_pi->dte_data.enable_dte_by_default) { -- cgit v0.10.2 From 27d470c1ab555a1c0b87099c242dc479e19076af Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Jul 2013 11:48:29 +0200 Subject: Revert "gpio/omap: fix build error when OF_GPIO is not defined." This reverts commit 949eb1a4d29dc75e0b5b16b03747886b52ecf854. Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index c57244e..3a0c160 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1037,18 +1037,6 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -#if defined(CONFIG_OF_GPIO) -static inline bool omap_gpio_chip_boot_dt(struct gpio_chip *chip) -{ - return chip->of_node != NULL; -} -#else -static inline bool omap_gpio_chip_boot_dt(struct gpio_chip *chip) -{ - return false; -} -#endif - static void omap_gpio_chip_init(struct gpio_bank *bank) { int j; @@ -1089,7 +1077,7 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) * irq_create_of_mapping() only for the GPIO lines that * are used as interrupts. */ - if (!omap_gpio_chip_boot_dt(&bank->chip)) + if (!bank->chip.of_node) for (j = 0; j < bank->width; j++) irq_create_mapping(bank->domain, j); irq_set_chained_handler(bank->irq, gpio_irq_handler); @@ -1125,7 +1113,7 @@ static int omap_gpio_irq_map(struct irq_domain *d, unsigned int virq, * but until then this has to be done on a per driver * basis. Remove this once this is managed by the core. */ - if (omap_gpio_chip_boot_dt(&bank->chip)) { + if (bank->chip.of_node) { gpio = irq_to_gpio(bank, hwirq); ret = gpio_request_one(gpio, GPIOF_IN, NULL); if (ret) { -- cgit v0.10.2 From c119fee06309a5b6969992b6fe2593299c803c81 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Jul 2013 11:48:54 +0200 Subject: Revert "gpio/omap: auto request GPIO as input if used as IRQ via DT" This reverts commit b4419e1a15905191661ffe75ba2f9e649f5d565e. Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 3a0c160..5e667ff 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1090,8 +1090,6 @@ static int omap_gpio_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { struct gpio_bank *bank = d->host_data; - int gpio; - int ret; if (!bank) return -EINVAL; @@ -1106,22 +1104,6 @@ static int omap_gpio_irq_map(struct irq_domain *d, unsigned int virq, set_irq_flags(virq, IRQF_VALID); } - /* - * REVISIT most GPIO IRQ chip drivers need to call - * gpio_request() before a GPIO line can be used as an - * IRQ. Ideally this should be handled by the IRQ core - * but until then this has to be done on a per driver - * basis. Remove this once this is managed by the core. - */ - if (bank->chip.of_node) { - gpio = irq_to_gpio(bank, hwirq); - ret = gpio_request_one(gpio, GPIOF_IN, NULL); - if (ret) { - dev_err(bank->dev, "Could not request GPIO%d\n", gpio); - return ret; - } - } - return 0; } -- cgit v0.10.2 From 253403b035ac55ddd00282ab2dc8e948facc0da6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 29 Jul 2013 11:49:21 +0200 Subject: Revert "gpio/omap: don't create an IRQ mapping for every GPIO on DT" This reverts commit 0e970cec05635adbe7b686063e2548a8e4afb8f4. Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5e667ff..dfeb3a3 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1068,50 +1068,24 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) gpiochip_add(&bank->chip); - /* - * REVISIT these explicit calls to irq_create_mapping() - * to do the GPIO to IRQ domain mapping for each GPIO in - * the bank can be removed once all OMAP platforms have - * been migrated to Device Tree boot only. - * Since in DT boot irq_create_mapping() is called from - * irq_create_of_mapping() only for the GPIO lines that - * are used as interrupts. - */ - if (!bank->chip.of_node) - for (j = 0; j < bank->width; j++) - irq_create_mapping(bank->domain, j); + for (j = 0; j < bank->width; j++) { + int irq = irq_create_mapping(bank->domain, j); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, bank); + if (bank->is_mpuio) { + omap_mpuio_alloc_gc(bank, irq, bank->width); + } else { + irq_set_chip_and_handler(irq, &gpio_irq_chip, + handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + } + } irq_set_chained_handler(bank->irq, gpio_irq_handler); irq_set_handler_data(bank->irq, bank); } static const struct of_device_id omap_gpio_match[]; -static int omap_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hwirq) -{ - struct gpio_bank *bank = d->host_data; - - if (!bank) - return -EINVAL; - - irq_set_lockdep_class(virq, &gpio_lock_class); - irq_set_chip_data(virq, bank); - if (bank->is_mpuio) { - omap_mpuio_alloc_gc(bank, virq, bank->width); - } else { - irq_set_chip_and_handler(virq, &gpio_irq_chip, - handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); - } - - return 0; -} - -static struct irq_domain_ops omap_gpio_irq_ops = { - .xlate = irq_domain_xlate_onetwocell, - .map = omap_gpio_irq_map, -}; - static int omap_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1177,10 +1151,10 @@ static int omap_gpio_probe(struct platform_device *pdev) } bank->domain = irq_domain_add_legacy(node, bank->width, irq_base, - 0, &omap_gpio_irq_ops, bank); + 0, &irq_domain_simple_ops, NULL); #else bank->domain = irq_domain_add_linear(node, bank->width, - &omap_gpio_irq_ops, bank); + &irq_domain_simple_ops, NULL); #endif if (!bank->domain) { dev_err(dev, "Couldn't register an IRQ domain\n"); -- cgit v0.10.2 From 011b2039dfd46fa030138b2e2ed3c55c8341151d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 24 Jul 2013 13:20:48 -0700 Subject: gpio_msm: Fix build error due to missing err.h drivers/gpio/gpio-msm-v1.c: In function 'gpio_msm_v1_probe': drivers/gpio/gpio-msm-v1.c:656:2: error: implicit declaration of function 'IS_ERR' [-Werror=implicit-function-declaration] drivers/gpio/gpio-msm-v1.c:657:3: error: implicit declaration of function 'PTR_ERR' [-Werror=implicit-function-declaration] This driver failed to compile after commit 68515bb (gpio_msm: Convert to use devm_ioremap_resource, 2013-06-10). Acked-by: Tushar Behera Signed-off-by: Stephen Boyd Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c index e3ceaac..73b7396 100644 --- a/drivers/gpio/gpio-msm-v1.c +++ b/drivers/gpio/gpio-msm-v1.c @@ -21,6 +21,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From 3c93f039d29326954b2c503a71e1eab9ae49063b Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 30 Jul 2013 15:48:35 -0700 Subject: Revert "RDMA/nes: Fix compilation error when nes_debug is enabled" This reverts commit bca1935ccdec, which removes variables nes_tcp_state_str and nes_iwarp_state_str, assuming that they aren't defined. However, they are defined within a #ifdef NES_DEBUG statement, which if enabled causes "defined but not used" compiler warning, when the variables are removed. Signed-off-by: Tatyana Nikolova Reported-by: Stephen Rothwell Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 418004c..9020024 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -3570,10 +3570,10 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT; iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT; nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p," - " Tcp state = %d, iWARP state = %d\n", + " Tcp state = %s, iWARP state = %s\n", async_event_id, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe, - tcp_state, iwarp_state); + nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]); aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]); if (aeq_info & NES_AEQE_QP) { -- cgit v0.10.2 From a264b981f2c76e281ef27e7232774bf6c54ec865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 30 Jul 2013 11:29:40 +0200 Subject: net/fec: Don't let ndo_start_xmit return NETDEV_TX_BUSY without link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't test for having link and let hardware deal with this situation. Without this patch I see a machine running an -rt patched Linux being stuck in sch_direct_xmit when it looses link while there is still a packet to be sent. In this case the fec_enet_start_xmit routine returned NETDEV_TX_BUSY which makes the network stack reschedule the packet and so sch_direct_xmit calls fec_enet_start_xmit again. I failed to reproduce a complete hang without -rt, but I think the problem exists there, too. Signed-off-by: Uwe Kleine-König Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 0dda454..77ea0db 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -294,11 +294,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) unsigned short status; unsigned int index; - if (!fep->link) { - /* Link is down or auto-negotiation is in progress. */ - return NETDEV_TX_BUSY; - } - /* Fill in a Tx ring entry */ bdp = fep->cur_tx; -- cgit v0.10.2 From 8fb488d740582314534c278b5d1e3a1888b850b9 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 24 Jul 2013 15:06:07 -0700 Subject: RDMA/cma: Fix gcc warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building cma.o triggers this gcc warning: drivers/infiniband/core/cma.c: In function ‘rdma_resolve_addr’: drivers/infiniband/core/cma.c:465:23: warning: ‘port’ may be used uninitialized in this function [-Wmaybe-uninitialized] drivers/infiniband/core/cma.c:426:5: note: ‘port’ was declared here This is a false positive, as "port" will always be initialized if we're at "found". But if we assign to "id_priv->id.port_num" directly, we can drop "port". That will, obviously, silence gcc. Signed-off-by: Paul Bolle Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index f1c279f..84487a2 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -423,7 +423,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) struct sockaddr_ib *addr; union ib_gid gid, sgid, *dgid; u16 pkey, index; - u8 port, p; + u8 p; int i; cma_dev = NULL; @@ -443,7 +443,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) if (!memcmp(&gid, dgid, sizeof(gid))) { cma_dev = cur_dev; sgid = gid; - port = p; + id_priv->id.port_num = p; goto found; } @@ -451,7 +451,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) dgid->global.subnet_prefix)) { cma_dev = cur_dev; sgid = gid; - port = p; + id_priv->id.port_num = p; } } } @@ -462,7 +462,6 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) found: cma_attach_to_dev(id_priv, cma_dev); - id_priv->id.port_num = port; addr = (struct sockaddr_ib *) cma_src_addr(id_priv); memcpy(&addr->sib_addr, &sgid, sizeof sgid); cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); -- cgit v0.10.2 From 9ea7187c53f63e31f2d1b2b1e474e31808565009 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 31 Jul 2013 01:19:43 +0200 Subject: NFC: netlink: Rename CMD_FW_UPLOAD to CMD_FW_DOWNLOAD Loading a firmware into a target is typically called firmware download, not firmware upload. So we rename the netlink API to NFC_CMD_FW_DOWNLOAD in order to avoid any terminology confusion from userspace. Signed-off-by: Samuel Ortiz diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index 0af851c..b64b7bc 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -59,7 +59,7 @@ struct nfc_hci_ops { struct nfc_target *target); int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, struct sk_buff *skb); - int (*fw_upload)(struct nfc_hci_dev *hdev, const char *firmware_name); + int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name); int (*discover_se)(struct nfc_hci_dev *dev); int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx); int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx); diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 0e353f1..5f286b7 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -68,7 +68,7 @@ struct nfc_ops { void *cb_context); int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb); int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target); - int (*fw_upload)(struct nfc_dev *dev, const char *firmware_name); + int (*fw_download)(struct nfc_dev *dev, const char *firmware_name); /* Secure Element API */ int (*discover_se)(struct nfc_dev *dev); @@ -127,7 +127,7 @@ struct nfc_dev { int targets_generation; struct device dev; bool dev_up; - bool fw_upload_in_progress; + bool fw_download_in_progress; u8 rf_mode; bool polling; struct nfc_target *active_target; diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index caed0f3..8137dd8 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -69,8 +69,8 @@ * starting a poll from a device which has a secure element enabled means * we want to do SE based card emulation. * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element. - * @NFC_CMD_FW_UPLOAD: Request to Load/flash firmware, or event to inform that - * some firmware was loaded + * @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform + * that some firmware was loaded */ enum nfc_commands { NFC_CMD_UNSPEC, @@ -94,7 +94,7 @@ enum nfc_commands { NFC_CMD_DISABLE_SE, NFC_CMD_LLC_SDREQ, NFC_EVENT_LLC_SDRES, - NFC_CMD_FW_UPLOAD, + NFC_CMD_FW_DOWNLOAD, NFC_EVENT_SE_ADDED, NFC_EVENT_SE_REMOVED, /* private: internal use only */ diff --git a/net/nfc/core.c b/net/nfc/core.c index dc96a83..1d074dd 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -44,7 +44,7 @@ DEFINE_MUTEX(nfc_devlist_mutex); /* NFC device ID bitmap */ static DEFINE_IDA(nfc_index_ida); -int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name) +int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name) { int rc = 0; @@ -62,28 +62,28 @@ int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name) goto error; } - if (!dev->ops->fw_upload) { + if (!dev->ops->fw_download) { rc = -EOPNOTSUPP; goto error; } - dev->fw_upload_in_progress = true; - rc = dev->ops->fw_upload(dev, firmware_name); + dev->fw_download_in_progress = true; + rc = dev->ops->fw_download(dev, firmware_name); if (rc) - dev->fw_upload_in_progress = false; + dev->fw_download_in_progress = false; error: device_unlock(&dev->dev); return rc; } -int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name) +int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name) { - dev->fw_upload_in_progress = false; + dev->fw_download_in_progress = false; - return nfc_genl_fw_upload_done(dev, firmware_name); + return nfc_genl_fw_download_done(dev, firmware_name); } -EXPORT_SYMBOL(nfc_fw_upload_done); +EXPORT_SYMBOL(nfc_fw_download_done); /** * nfc_dev_up - turn on the NFC device @@ -110,7 +110,7 @@ int nfc_dev_up(struct nfc_dev *dev) goto error; } - if (dev->fw_upload_in_progress) { + if (dev->fw_download_in_progress) { rc = -EBUSY; goto error; } diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 7b1c186..fe66908 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -809,14 +809,14 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) } } -static int hci_fw_upload(struct nfc_dev *nfc_dev, const char *firmware_name) +static int hci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - if (!hdev->ops->fw_upload) + if (!hdev->ops->fw_download) return -ENOTSUPP; - return hdev->ops->fw_upload(hdev, firmware_name); + return hdev->ops->fw_download(hdev, firmware_name); } static struct nfc_ops hci_nfc_ops = { @@ -831,7 +831,7 @@ static struct nfc_ops hci_nfc_ops = { .im_transceive = hci_transceive, .tm_send = hci_tm_send, .check_presence = hci_check_presence, - .fw_upload = hci_fw_upload, + .fw_download = hci_fw_download, .discover_se = hci_discover_se, .enable_se = hci_enable_se, .disable_se = hci_disable_se, diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index b05ad90..f16fd59 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1089,7 +1089,7 @@ exit: return rc; } -static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info) +static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info) { struct nfc_dev *dev; int rc; @@ -1108,13 +1108,13 @@ static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info) nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME], sizeof(firmware_name)); - rc = nfc_fw_upload(dev, firmware_name); + rc = nfc_fw_download(dev, firmware_name); nfc_put_device(dev); return rc; } -int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name) +int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name) { struct sk_buff *msg; void *hdr; @@ -1124,7 +1124,7 @@ int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name) return -ENOMEM; hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, - NFC_CMD_FW_UPLOAD); + NFC_CMD_FW_DOWNLOAD); if (!hdr) goto free_msg; @@ -1251,8 +1251,8 @@ static struct genl_ops nfc_genl_ops[] = { .policy = nfc_genl_policy, }, { - .cmd = NFC_CMD_FW_UPLOAD, - .doit = nfc_genl_fw_upload, + .cmd = NFC_CMD_FW_DOWNLOAD, + .doit = nfc_genl_fw_download, .policy = nfc_genl_policy, }, { diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index ee85a1f..820a785 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -123,10 +123,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter) class_dev_iter_exit(iter); } -int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name); -int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name); +int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name); +int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name); -int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name); +int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name); int nfc_dev_up(struct nfc_dev *dev); -- cgit v0.10.2 From ff862a4668dd6dba962b1d2d8bd344afa6375683 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 28 Jul 2013 23:04:45 +0300 Subject: af_key: more info leaks in pfkey messages This is inspired by a5cc68f3d6 "af_key: fix info leaks in notify messages". There are some struct members which don't get initialized and could disclose small amounts of private information. Acked-by: Mathias Krause Signed-off-by: Dan Carpenter Acked-by: Steffen Klassert Signed-off-by: David S. Miller diff --git a/net/key/af_key.c b/net/key/af_key.c index 9da8620..ab8bd2c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2081,6 +2081,7 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy * pol->sadb_x_policy_type = IPSEC_POLICY_NONE; } pol->sadb_x_policy_dir = dir+1; + pol->sadb_x_policy_reserved = 0; pol->sadb_x_policy_id = xp->index; pol->sadb_x_policy_priority = xp->priority; @@ -3137,7 +3138,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; pol->sadb_x_policy_dir = XFRM_POLICY_OUT + 1; + pol->sadb_x_policy_reserved = 0; pol->sadb_x_policy_id = xp->index; + pol->sadb_x_policy_priority = xp->priority; /* Set sadb_comb's. */ if (x->id.proto == IPPROTO_AH) @@ -3525,6 +3528,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; pol->sadb_x_policy_dir = dir + 1; + pol->sadb_x_policy_reserved = 0; pol->sadb_x_policy_id = 0; pol->sadb_x_policy_priority = 0; -- cgit v0.10.2 From e1ee3673a83cc02b6b5e43c9e647d8dd5e1c4e26 Mon Sep 17 00:00:00 2001 From: Pablo Neira Date: Mon, 29 Jul 2013 12:30:04 +0200 Subject: genetlink: fix usage of NLM_F_EXCL or NLM_F_REPLACE Currently, it is not possible to use neither NLM_F_EXCL nor NLM_F_REPLACE from genetlink. This is due to this checking in genl_family_rcv_msg: if (nlh->nlmsg_flags & NLM_F_DUMP) NLM_F_DUMP is NLM_F_MATCH|NLM_F_ROOT. Thus, if NLM_F_EXCL or NLM_F_REPLACE flag is set, genetlink believes that you're requesting a dump and it calls the .dumpit callback. The solution that I propose is to refine this checking to make it stricter: if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) And given the combination NLM_F_REPLACE and NLM_F_EXCL does not make sense to me, it removes the ambiguity. There was a patch that tried to fix this some time ago (0ab03c2 netlink: test for all flags of the NLM_F_DUMP composite) but it tried to resolve this ambiguity in *all* existing netlink subsystems, not only genetlink. That patch was reverted since it broke iproute2, which is using NLM_F_ROOT to request the dump of the routing cache. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 1076fe1..512718a 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -571,7 +571,7 @@ static int genl_family_rcv_msg(struct genl_family *family, !capable(CAP_NET_ADMIN)) return -EPERM; - if (nlh->nlmsg_flags & NLM_F_DUMP) { + if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) { struct netlink_dump_control c = { .dump = ops->dumpit, .done = ops->done, -- cgit v0.10.2 From e1b4d3036c07ff137955fb1c0197ab62534f46ec Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 30 Jul 2013 16:27:57 -0700 Subject: drm/i915: fix missed hunk after GT access breakage Upon some code refactoring, a hunk was missed. This was fixed for next, but missed the current trees, and hasn't yet been merged by Dave Airlie. It is fixed in: commit 907b28c56ea40629aa6595ddfa414ec2fc7da41c Author: Chris Wilson Date: Fri Jul 19 20:36:52 2013 +0100 drm/i915: Colocate all GT access routines in the same file It is introduced by: commit 181d1b9e31c668259d3798c521672afb8edd355c Author: Daniel Vetter Date: Sun Jul 21 13:16:24 2013 +0200 drm/i915: fix up gt init sequence fallout Reported-by: Dave Jones Cc: stable Signed-off-by: Ben Widawsky Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 66c6380..f466980 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1594,6 +1594,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_detect_pch(dev); intel_irq_init(dev); + intel_pm_init(dev); intel_gt_sanitize(dev); intel_gt_init(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d2ee334..1929bff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1582,6 +1582,7 @@ void i915_hangcheck_elapsed(unsigned long data); void i915_handle_error(struct drm_device *dev, bool wedged); extern void intel_irq_init(struct drm_device *dev); +extern void intel_pm_init(struct drm_device *dev); extern void intel_hpd_init(struct drm_device *dev); extern void intel_gt_init(struct drm_device *dev); extern void intel_gt_sanitize(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 51a2a60..f895d15 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5536,6 +5536,12 @@ void intel_gt_init(struct drm_device *dev) dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; } +} + +void intel_pm_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, intel_gen6_powersave_work); } -- cgit v0.10.2 From 7b70176421993866e616f1cbc4d0dd4054f1bf78 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 29 Jul 2013 10:24:04 -0700 Subject: atl1c: Fix misuse of netdev_alloc_skb in refilling rx ring On Mon, 2013-07-29 at 08:30 -0700, Eric Dumazet wrote: > On Mon, 2013-07-29 at 13:09 +0100, Luis Henriques wrote: > > > > > I confirm that I can't reproduce the issue using this patch. > > > > Thanks, I'll send a polished patch, as this one had an error if > build_skb() returns NULL (in case sk_buff allocation fails) Please try the following patch : It should use 2K frags instead of 4K for normal 1500 mtu Thanks ! [PATCH] atl1c: use custom skb allocator We had reports ( https://bugzilla.kernel.org/show_bug.cgi?id=54021 ) that using high order pages for skb allocations is problematic for atl1c We do not know exactly what the problem is, but we suspect that crossing 4K pages is not well supported by this hardware. Use a custom allocator, using page allocator and 2K fragments for optimal stack behavior. We might make this allocator generic in future kernels. Signed-off-by: Eric Dumazet Cc: Luis Henriques Cc: Neil Horman Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index b2bf324..0f05565 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h @@ -520,6 +520,9 @@ struct atl1c_adapter { struct net_device *netdev; struct pci_dev *pdev; struct napi_struct napi; + struct page *rx_page; + unsigned int rx_page_offset; + unsigned int rx_frag_size; struct atl1c_hw hw; struct atl1c_hw_stats hw_stats; struct mii_if_info mii; /* MII interface info */ diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 786a874..a36a760 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, struct net_device *dev) { + unsigned int head_size; int mtu = dev->mtu; adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; + + head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + adapter->rx_frag_size = roundup_pow_of_two(head_size); } static netdev_features_t atl1c_fix_features(struct net_device *netdev, @@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter) kfree(adapter->tpd_ring[0].buffer_info); adapter->tpd_ring[0].buffer_info = NULL; } + if (adapter->rx_page) { + put_page(adapter->rx_page); + adapter->rx_page = NULL; + } } /** @@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, skb_checksum_none_assert(skb); } +static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) +{ + struct sk_buff *skb; + struct page *page; + + if (adapter->rx_frag_size > PAGE_SIZE) + return netdev_alloc_skb(adapter->netdev, + adapter->rx_buffer_len); + + page = adapter->rx_page; + if (!page) { + adapter->rx_page = page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) + return NULL; + adapter->rx_page_offset = 0; + } + + skb = build_skb(page_address(page) + adapter->rx_page_offset, + adapter->rx_frag_size); + if (likely(skb)) { + adapter->rx_page_offset += adapter->rx_frag_size; + if (adapter->rx_page_offset >= PAGE_SIZE) + adapter->rx_page = NULL; + else + get_page(page); + } + return skb; +} + static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) { struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; @@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) while (next_info->flags & ATL1C_BUFFER_FREE) { rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); - skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); + skb = atl1c_alloc_skb(adapter); if (unlikely(!skb)) { if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, "alloc rx buffer failed\n"); -- cgit v0.10.2 From aded09555b7a0748a692d0d644ac54c10c1c0757 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard \\(Rtp\\)" Date: Mon, 29 Jul 2013 21:56:47 +0200 Subject: mvneta: Fix hang when loading the mvneta driver When the mvneta driver is compiled, it'll be loaded with clocks disabled. This implies that the clocks should be enabled again before any register access or it'll hang. To fix it: - enable clock earlier - move timer callback after setting timer.data Signed-off-by: Arnaud Patard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 712779f..3ac29c6 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2728,20 +2728,10 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); - pp->tx_done_timer.function = mvneta_tx_done_timer_callback; - init_timer(&pp->tx_done_timer); - clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); - pp->weight = MVNETA_RX_POLL_WEIGHT; pp->phy_node = phy_node; pp->phy_interface = phy_mode; - pp->base = of_iomap(dn, 0); - if (pp->base == NULL) { - err = -ENOMEM; - goto err_free_irq; - } - pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { err = PTR_ERR(pp->clk); @@ -2765,7 +2755,16 @@ static int mvneta_probe(struct platform_device *pdev) } } + pp->base = of_iomap(dn, 0); + if (pp->base == NULL) { + err = -ENOMEM; + goto err_free_irq; + } + pp->tx_done_timer.data = (unsigned long)dev; + pp->tx_done_timer.function = mvneta_tx_done_timer_callback; + init_timer(&pp->tx_done_timer); + clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags); pp->tx_ring_size = MVNETA_MAX_TXD; pp->rx_ring_size = MVNETA_MAX_RXD; -- cgit v0.10.2 From 5445eaf309ff2868c77354016505fc7315947a35 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard \\(Rtp\\)" Date: Mon, 29 Jul 2013 21:56:48 +0200 Subject: mvneta: Try to fix mvneta when compiled as module When the mvneta driver is compiled as module, the clock is disabled before it's loading. This will reset the registers values and all configuration made by the bootloader. This patch sets the "sgmii serdes configuration" register to a magical value found in: https://github.com/yellowback/ubuntu-precise-armadaxp/blob/master/arch/arm/mach-armadaxp/armada_xp_family/ctrlEnv/mvCtrlEnvLib.c With this change, the interrupts are working/generated and ethernet is working. Signed-off-by: Arnaud Patard Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3ac29c6..b017818 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -88,6 +88,8 @@ #define MVNETA_TX_IN_PRGRS BIT(1) #define MVNETA_TX_FIFO_EMPTY BIT(8) #define MVNETA_RX_MIN_FRAME_SIZE 0x247c +#define MVNETA_SGMII_SERDES_CFG 0x24A0 +#define MVNETA_SGMII_SERDES_PROTO 0x0cc7 #define MVNETA_TYPE_PRIO 0x24bc #define MVNETA_FORCE_UNI BIT(21) #define MVNETA_TXQ_CMD_1 0x24e4 @@ -655,6 +657,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp) val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); val |= MVNETA_GMAC2_PSC_ENABLE; mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); + + mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); } /* Start the Ethernet port RX and TX activity */ @@ -2735,11 +2739,17 @@ static int mvneta_probe(struct platform_device *pdev) pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { err = PTR_ERR(pp->clk); - goto err_unmap; + goto err_free_irq; } clk_prepare_enable(pp->clk); + pp->base = of_iomap(dn, 0); + if (pp->base == NULL) { + err = -ENOMEM; + goto err_clk; + } + dt_mac_addr = of_get_mac_address(dn); if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) { mac_from = "device tree"; @@ -2755,12 +2765,6 @@ static int mvneta_probe(struct platform_device *pdev) } } - pp->base = of_iomap(dn, 0); - if (pp->base == NULL) { - err = -ENOMEM; - goto err_free_irq; - } - pp->tx_done_timer.data = (unsigned long)dev; pp->tx_done_timer.function = mvneta_tx_done_timer_callback; init_timer(&pp->tx_done_timer); @@ -2775,7 +2779,7 @@ static int mvneta_probe(struct platform_device *pdev) err = mvneta_init(pp, phy_addr); if (err < 0) { dev_err(&pdev->dev, "can't init eth hal\n"); - goto err_clk; + goto err_unmap; } mvneta_port_power_up(pp, phy_mode); @@ -2805,10 +2809,10 @@ static int mvneta_probe(struct platform_device *pdev) err_deinit: mvneta_deinit(pp); -err_clk: - clk_disable_unprepare(pp->clk); err_unmap: iounmap(pp->base); +err_clk: + clk_disable_unprepare(pp->clk); err_free_irq: irq_dispose_mapping(dev->irq); err_free_netdev: -- cgit v0.10.2 From a661b43fd047ef501da43a19975415f861c7c3db Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 30 Jul 2013 07:57:06 +0800 Subject: mlx5: fix error return code in mlx5_alloc_uuars() Fix to return -ENOMEM from the ioremap error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 71d4a39..68f5d9c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari) uuari->uars[i].map = ioremap(addr, PAGE_SIZE); if (!uuari->uars[i].map) { mlx5_cmd_free_uar(dev, uuari->uars[i].index); + err = -ENOMEM; goto out_count; } mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n", -- cgit v0.10.2 From e511d1ae16745baca1e6d807c5b963716e8bdd01 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 24 Jul 2013 15:06:08 -0700 Subject: RDMA/cma: Fix accessing invalid private data for UD If a application is using AF_IB with a UD QP, but does not provide any private data, we will end up accessing invalid memory. Check for this case and handle it appropriately. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 84487a2..4314655 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2676,29 +2676,32 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, { struct ib_cm_sidr_req_param req; struct ib_cm_id *id; + void *private_data; int offset, ret; + memset(&req, 0, sizeof req); offset = cma_user_data_offset(id_priv); req.private_data_len = offset + conn_param->private_data_len; if (req.private_data_len < conn_param->private_data_len) return -EINVAL; if (req.private_data_len) { - req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); - if (!req.private_data) + private_data = kzalloc(req.private_data_len, GFP_ATOMIC); + if (!private_data) return -ENOMEM; } else { - req.private_data = NULL; + private_data = NULL; } if (conn_param->private_data && conn_param->private_data_len) - memcpy((void *) req.private_data + offset, - conn_param->private_data, conn_param->private_data_len); + memcpy(private_data + offset, conn_param->private_data, + conn_param->private_data_len); - if (req.private_data) { - ret = cma_format_hdr((void *) req.private_data, id_priv); + if (private_data) { + ret = cma_format_hdr(private_data, id_priv); if (ret) goto out; + req.private_data = private_data; } id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, @@ -2720,7 +2723,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, id_priv->cm_id.ib = NULL; } out: - kfree(req.private_data); + kfree(private_data); return ret; } -- cgit v0.10.2 From 5eb695c1773b439fb668127d3738d348a46a2748 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 24 Jul 2013 15:06:09 -0700 Subject: RDMA/cma: Only call cma_save_ib_info() for CM REQs Calling cma_save_ib_info() for CM SIDR REQs results in a crash accessing an invalid path record pointer. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 4314655..7c0f953 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -879,7 +879,8 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id { struct cma_hdr *hdr; - if (listen_id->route.addr.src_addr.ss_family == AF_IB) { + if ((listen_id->route.addr.src_addr.ss_family == AF_IB) && + (ib_event->event == IB_CM_REQ_RECEIVED)) { cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path); return 0; } -- cgit v0.10.2 From d2ee88d0aaacac664aff6ca5fc0bd7705d8f2414 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 31 Jul 2013 10:15:19 +0200 Subject: ASoC: au1x: Fix build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit d8b51c11ff5a70244753ba60abfd47088cf4dcd4 [ASoC: ac97c: Use module_platform_driver()] broke the build: CC sound/soc/au1x/ac97c.o /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: expected identifier or ‘(’ before ‘&’ token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: pasting "__initcall_" and "&" does not give a valid preprocessing token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘&’ token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: expected identifier or ‘(’ before ‘&’ token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: pasting "__exitcall_" and "&" does not give a valid preprocessing token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:344:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘&’ token /home/ralf/src/linux/upstream-sfr/sound/soc/au1x/ac97c.c:334:31: warning: ‘au1xac97c_driver’ defined but not used [-Wunused-variable] make[5]: *** [sound/soc/au1x/ac97c.o] Error 1 make[4]: *** [sound/soc/au1x] Error 2 make[3]: *** [sound/soc] Error 2 Signed-off-by: Ralf Baechle Signed-off-by: Mark Brown diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index d6f7694..c8a2de1 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c @@ -341,7 +341,7 @@ static struct platform_driver au1xac97c_driver = { .remove = au1xac97c_drvremove, }; -module_platform_driver(&au1xac97c_driver); +module_platform_driver(au1xac97c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver"); -- cgit v0.10.2 From bed859c1eea89feaba2acbb57d967a6d6f68af09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 30 Jul 2013 11:33:00 +0100 Subject: ARM: 7800/1: ARMv7-M: Fix name of NVIC handler function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name changed in response to review comments for the nvic irqchip driver when the original name was already accepted into Russell King's tree. Signed-off-by: Uwe Kleine-König Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S index e00621f..52b2643 100644 --- a/arch/arm/kernel/entry-v7m.S +++ b/arch/arm/kernel/entry-v7m.S @@ -49,7 +49,7 @@ __irq_entry: mov r1, sp stmdb sp!, {lr} @ routine called with r0 = irq number, r1 = struct pt_regs * - bl nvic_do_IRQ + bl nvic_handle_irq pop {lr} @ -- cgit v0.10.2 From 067e710b9a982a92cc8294d7fa0f1e924c65bba1 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 30 Jul 2013 12:38:45 +0100 Subject: ARM: 7801/1: v6: prevent gcc 4.5 from reordering extended CP15 reads above is_smp() test Commit 621a0147d5c921f4cc33636ccd0602ad5d7cbfbc ("ARM: 7757/1: mm: don't flush icache in switch_mm with hardware broadcasting") breaks the boot on OMAP2430SDP with omap2plus_defconfig. Tracked to an undefined instruction abort from the CP15 read in cache_ops_need_broadcast(). It turns out that gcc 4.5 reorders the extended CP15 read above the is_smp() test. This breaks ARM1136 r0 cores, since they don't support several CP15 registers that later ARM cores do. ARM1136JF-S TRM section 3.2.1 "Register allocation" has the details. So mark the extended CP15 read as clobbering memory, which prevents the compiler from reordering it before the is_smp() test. Russell states that the code generated from this approach is preferable to marking the inline asm as volatile. Remove the existing condition code clobber as it's obsolete, per Nico's post: http://www.spinics.net/lists/arm-kernel/msg261208.html This patch is a collaboration with Will Deacon and Russell King. Comments from Paul Walmsley: Russell, if you accept this one, might you also add Will's ack from the lists: Comments from Paul Walmsley: I'd also be obliged if you could add a Cc: line for Jonathan Austin, since he helped test: Signed-off-by: Paul Walmsley Cc: Will Deacon Cc: Nicolas Pitre Cc: Tony Lindgren Acked-by: Will Deacon Cc: Jonathan Austin Signed-off-by: Russell King diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index 8c25dc4..9672e97 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -89,13 +89,18 @@ extern unsigned int processor_id; __val; \ }) +/* + * The memory clobber prevents gcc 4.5 from reordering the mrc before + * any is_smp() tests, which can cause undefined instruction aborts on + * ARM1136 r0 due to the missing extended CP15 registers. + */ #define read_cpuid_ext(ext_reg) \ ({ \ unsigned int __val; \ asm("mrc p15, 0, %0, c0, " ext_reg \ : "=r" (__val) \ : \ - : "cc"); \ + : "memory"); \ __val; \ }) -- cgit v0.10.2 From 4f8b19143d74e1c3360b21640065765a12bafb1b Mon Sep 17 00:00:00 2001 From: Dimitris Papastamos Date: Wed, 31 Jul 2013 13:28:52 +0100 Subject: ASoC: wm0010: Fix resource leak If kzalloc() fails for `img' then we are going to leak the memory for `out'. We are freeing the memory of all the tx/rx transfers but the tx/rx buf pointers will be NULL if we drop out earlier. Signed-off-by: Dimitris Papastamos Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index f5e8356..10adc41 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -410,6 +410,16 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) rec->command, rec->length); len = rec->length + 8; + xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); + if (!xfer) { + dev_err(codec->dev, "Failed to allocate xfer\n"); + ret = -ENOMEM; + goto abort; + } + + xfer->codec = codec; + list_add_tail(&xfer->list, &xfer_list); + out = kzalloc(len, GFP_KERNEL); if (!out) { dev_err(codec->dev, @@ -417,6 +427,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) ret = -ENOMEM; goto abort1; } + xfer->t.rx_buf = out; img = kzalloc(len, GFP_KERNEL); if (!img) { @@ -425,24 +436,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec) ret = -ENOMEM; goto abort1; } + xfer->t.tx_buf = img; byte_swap_64((u64 *)&rec->command, img, len); - xfer = kzalloc(sizeof(*xfer), GFP_KERNEL); - if (!xfer) { - dev_err(codec->dev, "Failed to allocate xfer\n"); - ret = -ENOMEM; - goto abort1; - } - - xfer->codec = codec; - list_add_tail(&xfer->list, &xfer_list); - spi_message_init(&xfer->m); xfer->m.complete = wm0010_boot_xfer_complete; xfer->m.context = xfer; - xfer->t.tx_buf = img; - xfer->t.rx_buf = out; xfer->t.len = len; xfer->t.bits_per_word = 8; -- cgit v0.10.2 From 8e552e535948fe8612d36a7beaf19519140bc285 Mon Sep 17 00:00:00 2001 From: Yonghua Zheng Date: Tue, 30 Jul 2013 14:16:10 +0800 Subject: HID: hidraw: fix improper mutex release Mutex can not be released unless all hid_device members are properly initialized. Otherwise it would result in a race condition that can cause NULL pointer kernel panic issue in hidraw_open where it uses uninitialized 'list' member in list_add_tail(). Signed-off-by: Yonghua Zheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index a745163..6f1feb2 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -518,7 +518,6 @@ int hidraw_connect(struct hid_device *hid) goto out; } - mutex_unlock(&minors_lock); init_waitqueue_head(&dev->wait); INIT_LIST_HEAD(&dev->list); @@ -528,6 +527,7 @@ int hidraw_connect(struct hid_device *hid) dev->exist = 1; hid->hidraw = dev; + mutex_unlock(&minors_lock); out: return result; -- cgit v0.10.2 From 953b3539ef9301b8ef73f4b6e2fd824b86aae65a Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 29 Jul 2013 16:32:37 -0700 Subject: mwifiex: check for bss_role instead of bss_mode for STA operations This patch fixes an issue wherein association would fail on P2P interfaces. This happened because we are checking priv->mode against NL80211_IFTYPE_STATION. While this check is correct for infrastructure stations, it would fail P2P clients for which mode is NL80211_IFTYPE_P2P_CLIENT. Better check would be bss_role which has only 2 values: STA/AP. Cc: # 3.10.y Signed-off-by: Avinash Patil Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ef5fa89..89459db 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1716,9 +1716,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret; - if (priv->bss_mode != NL80211_IFTYPE_STATION) { + if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { wiphy_err(wiphy, - "%s: reject infra assoc request in non-STA mode\n", + "%s: reject infra assoc request in non-STA role\n", dev->name); return -EINVAL; } diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 1c8a771..12e7781 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv, { u8 current_bssid[ETH_ALEN]; - /* Return error if the adapter or table entry is not marked as infra */ - if ((priv->bss_mode != NL80211_IFTYPE_STATION) || + /* Return error if the adapter is not STA role or table entry + * is not marked as infra. + */ + if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) return -1; -- cgit v0.10.2 From 237b2ac8ac89a6b0120decdd05c7bf4637deb98a Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 29 Jul 2013 16:32:38 -0700 Subject: mwifiex: fix wrong data rates in P2P client This patch fixes an issue wherein adhoc rates were being copied into association request from P2P client. Cc: # 3.10.y Signed-off-by: Avinash Patil Signed-off-by: Stone Piao Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 988552d..5178c46 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -415,7 +415,8 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates) u32 k = 0; struct mwifiex_adapter *adapter = priv->adapter; - if (priv->bss_mode == NL80211_IFTYPE_STATION) { + if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { switch (adapter->config_bands) { case BAND_B: dev_dbg(adapter->dev, "info: infra band=%d " -- cgit v0.10.2 From 6621fe18cdce50df9c3954f878183321dfe3078c Mon Sep 17 00:00:00 2001 From: Stone Piao Date: Mon, 29 Jul 2013 16:32:39 -0700 Subject: mwifiex: fix command 0x2c timeout during p2p_find or p2p_connect We missed bss_mode check for P2P client. Signed-off-by: Stone Piao Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 206c3e0..8af97ab 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - if (priv->bss_mode == NL80211_IFTYPE_STATION) { + if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { u8 config_bands; - /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) goto done; -- cgit v0.10.2 From d6158a55738863b3fe2d48bbb3bf33005ef834b8 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Tue, 30 Jul 2013 20:45:41 +0300 Subject: MAINTAINERS: change email of TI WiLink drivers' maintainer Soon the coelho@ti.com email will not be valid anymore, so change it to my private one. Cc: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/MAINTAINERS b/MAINTAINERS index 7a403ba..6447bec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8272,7 +8272,7 @@ S: Maintained F: sound/soc/codecs/twl4030* TI WILINK WIRELESS DRIVERS -M: Luciano Coelho +M: Luciano Coelho L: linux-wireless@vger.kernel.org W: http://wireless.kernel.org/en/users/Drivers/wl12xx W: http://wireless.kernel.org/en/users/Drivers/wl1251 -- cgit v0.10.2 From 3eac103f83ab0c2013b734981d92d56be51a1a9c Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 18 Jul 2013 14:02:30 +0300 Subject: IB/mlx4: Use default pkey when creating tunnel QPs When creating tunnel QPs for special QP tunneling, look for the default pkey in the slave's virtual pkey table. If it is present, use the real pkey index where the default pkey is located. If the default pkey is not found in the pkey table, use the real pkey index which is stored at index 0 in the slave's virtual pkey table (this is the current behavior). This change is required to support cloud computing, where the paravirtualized index of the default pkey is moved to index 1 or higher. The pkey at paravirtualized index 0 is used for the default IPoIB interface created by the VF. Its possible for the pkey value at paravirtualized index 0 to be invalid (zero) at VF probe time (pkey index 0 is mapped to real pkey index 127, which contains pkey = 0). At some point after the VF probe, the cloud computing interface at the hypervisor maps virtual index 0 for the VF to the pkey index containing the pkey that IPoIB will use in its operation. However, when the tunnel QP is created, the pkey at the slave's virtual index 0 is still mapped to the invalid pkey index, so tunnel QP creation fails. This commit causes the hypervisor to search for the default pkey in the slave's pkey table -- and this pkey is present in the table (at index > 0) at tunnel QP creation time, so that the tunnel QP creation will succeed. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 4d599ce..f2a3f48 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1511,8 +1511,14 @@ static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, memset(&attr, 0, sizeof attr); attr.qp_state = IB_QPS_INIT; - attr.pkey_index = - to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; + ret = 0; + if (create_tun) + ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave, + ctx->port, IB_DEFAULT_PKEY_FULL, + &attr.pkey_index); + if (ret || !create_tun) + attr.pkey_index = + to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; attr.qkey = IB_QP1_QKEY; attr.port_num = ctx->port; ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); -- cgit v0.10.2 From f928d4f2a86f46b030fa0850385b4391fc2b5918 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 Jul 2013 11:00:23 +0100 Subject: ARM: poison the vectors page Fill the empty regions of the vectors page with an exception generating instruction. This ensures that any inappropriate branch to the vector page is appropriately trapped, rather than just encountering some code to execute. (The vectors page was filled with zero before, which corresponds with the "andeq r0, r0, r0" instruction - a no-op.) Cc: Acked-by Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index cab094c..9433e8a 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -818,10 +818,20 @@ void __init early_trap_init(void *vectors_base) extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; + unsigned i; vectors_page = vectors_base; /* + * Poison the vectors page with an undefined instruction. This + * instruction is chosen to be undefined for both ARM and Thumb + * ISAs. The Thumb version is an undefined instruction with a + * branch back to the undefined instruction. + */ + for (i = 0; i < PAGE_SIZE / sizeof(u32); i++) + ((u32 *)vectors_base)[i] = 0xe7fddef1; + + /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) * into the vector page, mapped at 0xffff0000, and ensure these * are visible to the instruction stream. -- cgit v0.10.2 From 5b43e7a383d69381ffe53423e46dd0fafae07da3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 Jul 2013 11:32:04 +0100 Subject: ARM: poison memory between kuser helpers Poison the memory between each kuser helper. This ensures that any branch between the kuser helpers will be appropriately trapped. Cc: Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index a39cfc2a1..0243734 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -742,6 +742,17 @@ ENDPROC(__switch_to) #endif .endm + .macro kuser_pad, sym, size + .if (. - \sym) & 3 + .rept 4 - (. - \sym) & 3 + .byte 0 + .endr + .endif + .rept (\size - (. - \sym)) / 4 + .word 0xe7fddef1 + .endr + .endm + .align 5 .globl __kuser_helper_start __kuser_helper_start: @@ -832,18 +843,13 @@ kuser_cmpxchg64_fixup: #error "incoherent kernel configuration" #endif - /* pad to next slot */ - .rept (16 - (. - __kuser_cmpxchg64)/4) - .word 0 - .endr - - .align 5 + kuser_pad __kuser_cmpxchg64, 64 __kuser_memory_barrier: @ 0xffff0fa0 smp_dmb arm usr_ret lr - .align 5 + kuser_pad __kuser_memory_barrier, 32 __kuser_cmpxchg: @ 0xffff0fc0 @@ -916,13 +922,14 @@ kuser_cmpxchg32_fixup: #endif - .align 5 + kuser_pad __kuser_cmpxchg, 32 __kuser_get_tls: @ 0xffff0fe0 ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init usr_ret lr mrc p15, 0, r0, c13, c0, 3 @ 0xffff0fe8 hardware TLS code - .rep 4 + kuser_pad __kuser_get_tls, 16 + .rep 3 .word 0 @ 0xffff0ff0 software TLS value, then .endr @ pad up to __kuser_helper_version -- cgit v0.10.2 From 19accfd373847ac3d10623c5d20f948846299741 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 Jul 2013 11:40:32 +0100 Subject: ARM: move vector stubs Move the machine vector stubs into the page above the vector page, which we can prevent from being visible to userspace. Also move the reset stub, and place the swi vector at a location that the 'ldr' can get to it. This hides pointers into the kernel which could give valuable information to attackers, and reduces the number of exploitable instructions at a fixed address. Cc: Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba412e0..123b792 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -218,7 +218,8 @@ config VECTORS_BASE default DRAM_BASE if REMAP_VECTORS_TO_RAM default 0x00000000 help - The base address of exception vectors. + The base address of exception vectors. This must be two pages + in size. config ARM_PATCH_PHYS_VIRT bool "Patch physical to virtual translations at runtime" if EMBEDDED diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 0243734..79a41fa 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -944,9 +944,9 @@ __kuser_helper_end: /* * Vector stubs. * - * This code is copied to 0xffff0200 so we can use branches in the - * vectors, rather than ldr's. Note that this code must not - * exceed 0x300 bytes. + * This code is copied to 0xffff1000 so we can use branches in the + * vectors, rather than ldr's. Note that this code must not exceed + * a page size. * * Common stub entry macro: * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC @@ -995,6 +995,15 @@ ENDPROC(vector_\name) .globl __stubs_start __stubs_start: + @ This must be the first word + .word vector_swi + +vector_rst: + ARM( swi SYS_ERROR0 ) + THUMB( svc #0 ) + THUMB( nop ) + b vector_und + /* * Interrupt dispatcher */ @@ -1089,6 +1098,16 @@ __stubs_start: .align 5 /*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen, and won't happen in 32-bit data mode). + */ + +vector_addrexcptn: + b vector_addrexcptn + +/*============================================================================= * Undefined FIQs *----------------------------------------------------------------------------- * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC @@ -1101,35 +1120,14 @@ __stubs_start: vector_fiq: subs pc, lr, #4 -/*============================================================================= - * Address exception handler - *----------------------------------------------------------------------------- - * These aren't too critical. - * (they're not supposed to happen, and won't happen in 32-bit data mode). - */ - -vector_addrexcptn: - b vector_addrexcptn - -/* - * We group all the following data together to optimise - * for CPUs with separate I & D caches. - */ - .align 5 - -.LCvswi: - .word vector_swi - .globl __stubs_end __stubs_end: - .equ stubs_offset, __vectors_start + 0x200 - __stubs_start + .equ stubs_offset, __vectors_start + 0x1000 - __stubs_start .globl __vectors_start __vectors_start: - ARM( swi SYS_ERROR0 ) - THUMB( svc #0 ) - THUMB( nop ) + W(b) vector_rst + stubs_offset W(b) vector_und + stubs_offset W(ldr) pc, .LCvswi + stubs_offset W(b) vector_pabt + stubs_offset diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 9433e8a..2c8c7fa 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -837,7 +837,7 @@ void __init early_trap_init(void *vectors_base) * are visible to the instruction stream. */ memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); - memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); + memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start); memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); /* @@ -852,7 +852,7 @@ void __init early_trap_init(void *vectors_base) memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), sigreturn_codes, sizeof(sigreturn_codes)); - flush_icache_range(vectors, vectors + PAGE_SIZE); + flush_icache_range(vectors, vectors + PAGE_SIZE * 2); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); #else /* ifndef CONFIG_CPU_V7M */ /* diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 4f56617..9ea274d 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1160,7 +1160,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc) /* * Allocate the vector page early. */ - vectors = early_alloc(PAGE_SIZE); + vectors = early_alloc(PAGE_SIZE * 2); early_trap_init(vectors); @@ -1210,10 +1210,18 @@ static void __init devicemaps_init(struct machine_desc *mdesc) if (!vectors_high()) { map.virtual = 0; + map.length = PAGE_SIZE * 2; map.type = MT_LOW_VECTORS; create_mapping(&map); } + /* Now create a kernel read-only mapping */ + map.pfn += 1; + map.virtual = 0xffff0000 + PAGE_SIZE; + map.length = PAGE_SIZE; + map.type = MT_LOW_VECTORS; + create_mapping(&map); + /* * Ask the machine support to map in the statically mapped devices. */ -- cgit v0.10.2 From b9b32bf70f2fb710b07c94e13afbc729afe221da Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 4 Jul 2013 12:03:31 +0100 Subject: ARM: use linker magic for vectors and vector stubs Use linker magic to create the vectors and vector stubs: we can tell the linker to place them at an appropriate VMA, but keep the LMA within the kernel. This gets rid of some unnecessary symbol manipulation, and have the linker calculate the relocations appropriately. Cc: Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 79a41fa..7e1ae91 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -993,7 +993,7 @@ ENDPROC(vector_\name) 1: .endm - .globl __stubs_start + .section .stubs, "ax", %progbits __stubs_start: @ This must be the first word .word vector_swi @@ -1120,24 +1120,16 @@ vector_addrexcptn: vector_fiq: subs pc, lr, #4 - .globl __stubs_end -__stubs_end: - - .equ stubs_offset, __vectors_start + 0x1000 - __stubs_start - - .globl __vectors_start + .section .vectors, "ax", %progbits __vectors_start: - W(b) vector_rst + stubs_offset - W(b) vector_und + stubs_offset - W(ldr) pc, .LCvswi + stubs_offset - W(b) vector_pabt + stubs_offset - W(b) vector_dabt + stubs_offset - W(b) vector_addrexcptn + stubs_offset - W(b) vector_irq + stubs_offset - W(b) vector_fiq + stubs_offset - - .globl __vectors_end -__vectors_end: + W(b) vector_rst + W(b) vector_und + W(ldr) pc, __vectors_start + 0x1000 + W(b) vector_pabt + W(b) vector_dabt + W(b) vector_addrexcptn + W(b) vector_irq + W(b) vector_fiq .data diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index fa25e4e..7bcee5c 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -148,6 +148,23 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_begin = .; #endif + /* + * The vectors and stubs are relocatable code, and the + * only thing that matters is their relative offsets + */ + __vectors_start = .; + .vectors 0 : AT(__vectors_start) { + *(.vectors) + } + . = __vectors_start + SIZEOF(.vectors); + __vectors_end = .; + + __stubs_start = .; + .stubs 0x1000 : AT(__stubs_start) { + *(.stubs) + } + . = __stubs_start + SIZEOF(.stubs); + __stubs_end = .; INIT_TEXT_SECTION(8) .exit.text : { -- cgit v0.10.2 From e39e3f3ebfef03450cf7bfa7a974a8c61f7980c8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 9 Jul 2013 01:03:17 +0100 Subject: ARM: update FIQ support for relocation of vectors FIQ should no longer copy the FIQ code into the user visible vector page. Instead, it should use the hidden page. This change makes that happen. Cc: Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7e1ae91..94caefb 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -1120,6 +1120,9 @@ vector_addrexcptn: vector_fiq: subs pc, lr, #4 + .globl vector_fiq_offset + .equ vector_fiq_offset, vector_fiq + .section .vectors, "ax", %progbits __vectors_start: W(b) vector_rst diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c index 2adda11..25442f4 100644 --- a/arch/arm/kernel/fiq.c +++ b/arch/arm/kernel/fiq.c @@ -47,6 +47,11 @@ #include #include +#define FIQ_OFFSET ({ \ + extern void *vector_fiq_offset; \ + (unsigned)&vector_fiq_offset; \ + }) + static unsigned long no_fiq_insn; /* Default reacquire function @@ -80,13 +85,16 @@ int show_fiq_list(struct seq_file *p, int prec) void set_fiq_handler(void *start, unsigned int length) { #if defined(CONFIG_CPU_USE_DOMAINS) - memcpy((void *)0xffff001c, start, length); + void *base = (void *)0xffff0000; #else - memcpy(vectors_page + 0x1c, start, length); + void *base = vectors_page; #endif - flush_icache_range(0xffff001c, 0xffff001c + length); + unsigned offset = FIQ_OFFSET; + + memcpy(base + offset, start, length); + flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length); if (!vectors_high()) - flush_icache_range(0x1c, 0x1c + length); + flush_icache_range(offset, offset + length); } int claim_fiq(struct fiq_handler *f) @@ -144,6 +152,7 @@ EXPORT_SYMBOL(disable_fiq); void __init init_FIQ(int start) { - no_fiq_insn = *(unsigned long *)0xffff001c; + unsigned offset = FIQ_OFFSET; + no_fiq_insn = *(unsigned long *)(0xffff0000 + offset); fiq_start = start; } -- cgit v0.10.2 From f6f91b0d9fd971c630cef908dde8fe8795aefbf8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 23 Jul 2013 18:37:00 +0100 Subject: ARM: allow kuser helpers to be removed from the vector page Provide a kernel configuration option to allow the kernel user helpers to be removed from the vector page, thereby preventing their use with ROP (return orientated programming) attacks. This option is only visible for CPU architectures which natively support all the operations which kernel user helpers would normally provide, and must be enabled with caution. Cc: Acked-by: Nicolas Pitre Signed-off-by: Russell King diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 94caefb..d40d0ef 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -753,6 +753,7 @@ ENDPROC(__switch_to) .endr .endm +#ifdef CONFIG_KUSER_HELPERS .align 5 .globl __kuser_helper_start __kuser_helper_start: @@ -939,6 +940,8 @@ __kuser_helper_version: @ 0xffff0ffc .globl __kuser_helper_end __kuser_helper_end: +#endif + THUMB( .thumb ) /* diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 2c8c7fa..e3ca35c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -800,15 +800,26 @@ void __init trap_init(void) return; } -static void __init kuser_get_tls_init(unsigned long vectors) +#ifdef CONFIG_KUSER_HELPERS +static void __init kuser_init(void *vectors) { + extern char __kuser_helper_start[], __kuser_helper_end[]; + int kuser_sz = __kuser_helper_end - __kuser_helper_start; + + memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); + /* * vectors + 0xfe0 = __kuser_get_tls * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8 */ if (tls_emu || has_tls_reg) - memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4); + memcpy(vectors + 0xfe0, vectors + 0xfe8, 4); +} +#else +static void __init kuser_init(void *vectors) +{ } +#endif void __init early_trap_init(void *vectors_base) { @@ -816,8 +827,6 @@ void __init early_trap_init(void *vectors_base) unsigned long vectors = (unsigned long)vectors_base; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; - extern char __kuser_helper_start[], __kuser_helper_end[]; - int kuser_sz = __kuser_helper_end - __kuser_helper_start; unsigned i; vectors_page = vectors_base; @@ -838,12 +847,8 @@ void __init early_trap_init(void *vectors_base) */ memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start); - memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); - /* - * Do processor specific fixups for the kuser helpers - */ - kuser_get_tls_init(vectors); + kuser_init(vectors_base); /* * Copy signal return handlers into the vector page, and diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 6cacdc8..db5c2ca 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -421,24 +421,28 @@ config CPU_32v3 select CPU_USE_DOMAINS if MMU select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select TLS_REG_EMUL if SMP || !MMU + select NEED_KUSER_HELPERS config CPU_32v4 bool select CPU_USE_DOMAINS if MMU select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select TLS_REG_EMUL if SMP || !MMU + select NEED_KUSER_HELPERS config CPU_32v4T bool select CPU_USE_DOMAINS if MMU select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select TLS_REG_EMUL if SMP || !MMU + select NEED_KUSER_HELPERS config CPU_32v5 bool select CPU_USE_DOMAINS if MMU select NEEDS_SYSCALL_FOR_CMPXCHG if SMP select TLS_REG_EMUL if SMP || !MMU + select NEED_KUSER_HELPERS config CPU_32v6 bool @@ -776,6 +780,7 @@ config CPU_BPREDICT_DISABLE config TLS_REG_EMUL bool + select NEED_KUSER_HELPERS help An SMP system using a pre-ARMv6 processor (there are apparently a few prototypes like that in existence) and therefore access to @@ -783,11 +788,40 @@ config TLS_REG_EMUL config NEEDS_SYSCALL_FOR_CMPXCHG bool + select NEED_KUSER_HELPERS help SMP on a pre-ARMv6 processor? Well OK then. Forget about fast user space cmpxchg support. It is just not possible. +config NEED_KUSER_HELPERS + bool + +config KUSER_HELPERS + bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS + default y + help + Warning: disabling this option may break user programs. + + Provide kuser helpers in the vector page. The kernel provides + helper code to userspace in read only form at a fixed location + in the high vector page to allow userspace to be independent of + the CPU type fitted to the system. This permits binaries to be + run on ARMv4 through to ARMv7 without modification. + + However, the fixed address nature of these helpers can be used + by ROP (return orientated programming) authors when creating + exploits. + + If all of the binaries and libraries which run on your platform + are built specifically for your platform, and make no use of + these helpers, then you can turn this option off. However, + when such an binary or library is run, it will receive a SIGILL + signal, which will terminate the program. + + Say N here only if you are absolutely certain that you do not + need these helpers; otherwise, the safe option is to say Y. + config DMA_CACHE_RWFO bool "Enable read/write for ownership DMA cache maintenance" depends on CPU_V6K && SMP -- cgit v0.10.2 From 281d1a9211986cfdccbefcd6128049a0a0d473b2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 30 Jul 2013 07:54:26 +0800 Subject: IB/mlx5: Fix error return code in init_one() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 8000fff..b1cbf33 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1426,7 +1426,8 @@ static int init_one(struct pci_dev *pdev, if (err) goto err_eqs; - if (ib_register_device(&dev->ib_dev, NULL)) + err = ib_register_device(&dev->ib_dev, NULL); + if (err) goto err_rsrc; err = create_umr_res(dev); @@ -1434,8 +1435,9 @@ static int init_one(struct pci_dev *pdev, goto err_dev; for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) { - if (device_create_file(&dev->ib_dev.dev, - mlx5_class_attributes[i])) + err = device_create_file(&dev->ib_dev.dev, + mlx5_class_attributes[i]); + if (err) goto err_umrc; } -- cgit v0.10.2 From 92b0ca7cb149d20bd97a2ad88d860745045a77dc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Jul 2013 20:04:36 +0300 Subject: IB/mlx5: Fix stack info leak in mlx5_ib_alloc_ucontext() We don't set "resp.reserved". Since it's at the end of the struct that means we don't have to copy it to the user. Signed-off-by: Dan Carpenter Acked-by: Eli Cohen Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b1cbf33..3f831de 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -619,7 +619,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, resp.tot_uuars = req.total_num_uuars; resp.num_ports = dev->mdev.caps.num_ports; - err = ib_copy_to_udata(udata, &resp, sizeof(resp)); + err = ib_copy_to_udata(udata, &resp, + sizeof(resp) - sizeof(resp.reserved)); if (err) goto out_uars; -- cgit v0.10.2 From 11940c8728b8e4bd67d0afacefbb9391ff8f4201 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jul 2013 11:02:01 +0300 Subject: mlx5_core: Fix use after free in mlx5_cmd_comp_handler() We can't dereference "ent" after passing it to free_cmd(). Signed-off-by: Dan Carpenter Acked-by: Eli Cohen Signed-off-by: Roland Dreier diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 205753a..4037406 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1113,7 +1113,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) for (i = 0; i < (1 << cmd->log_sz); i++) { if (test_bit(i, &vector)) { + struct semaphore *sem; + ent = cmd->ent_arr[i]; + if (ent->page_queue) + sem = &cmd->pages_sem; + else + sem = &cmd->sem; ktime_get_ts(&ent->ts2); memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out)); dump_command(dev, ent, 0); @@ -1136,10 +1142,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector) } else { complete(&ent->done); } - if (ent->page_queue) - up(&cmd->pages_sem); - else - up(&cmd->sem); + up(sem); } } } -- cgit v0.10.2 From cd23b14b654769db83c9684ae1ba32c0e066670f Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 18 Jul 2013 15:31:08 +0300 Subject: mlx5_core: Implement new initialization sequence Introduce enbale_hca and disable_hca commands to signify when the driver starts or ceases to operate on the device. In addition the driver will use boot and init pages count; boot pages is required to allow firmware to complete boot commands and the other to complete init hca. Command interface revision is bumped to 4 to enforce using supported firmware. This patch breaks compatibility with old versions of firmware (< 4); however, the first GA firmware we will publish will support version 4 so this should not be a problem. Signed-off-by: Eli Cohen Signed-off-by: Roland Dreier diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 4037406..c571de8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -46,7 +46,7 @@ #include "mlx5_core.h" enum { - CMD_IF_REV = 3, + CMD_IF_REV = 4, }; enum { @@ -282,6 +282,12 @@ const char *mlx5_command_str(int command) case MLX5_CMD_OP_TEARDOWN_HCA: return "TEARDOWN_HCA"; + case MLX5_CMD_OP_ENABLE_HCA: + return "MLX5_CMD_OP_ENABLE_HCA"; + + case MLX5_CMD_OP_DISABLE_HCA: + return "MLX5_CMD_OP_DISABLE_HCA"; + case MLX5_CMD_OP_QUERY_PAGES: return "QUERY_PAGES"; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 12242de..b47739b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev) return err; } +static int mlx5_core_enable_hca(struct mlx5_core_dev *dev) +{ + int err; + struct mlx5_enable_hca_mbox_in in; + struct mlx5_enable_hca_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) + return err; + + if (out.hdr.status) + return mlx5_cmd_status_to_err(&out.hdr); + + return 0; +} + +static int mlx5_core_disable_hca(struct mlx5_core_dev *dev) +{ + int err; + struct mlx5_disable_hca_mbox_in in; + struct mlx5_disable_hca_mbox_out out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) + return err; + + if (out.hdr.status) + return mlx5_cmd_status_to_err(&out.hdr); + + return 0; +} + int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) } mlx5_pagealloc_init(dev); + + err = mlx5_core_enable_hca(dev); + if (err) { + dev_err(&pdev->dev, "enable hca failed\n"); + goto err_pagealloc_cleanup; + } + + err = mlx5_satisfy_startup_pages(dev, 1); + if (err) { + dev_err(&pdev->dev, "failed to allocate boot pages\n"); + goto err_disable_hca; + } + err = set_hca_ctrl(dev); if (err) { dev_err(&pdev->dev, "set_hca_ctrl failed\n"); - goto err_pagealloc_cleanup; + goto reclaim_boot_pages; } err = handle_hca_cap(dev); if (err) { dev_err(&pdev->dev, "handle_hca_cap failed\n"); - goto err_pagealloc_cleanup; + goto reclaim_boot_pages; } - err = mlx5_satisfy_startup_pages(dev); + err = mlx5_satisfy_startup_pages(dev, 0); if (err) { - dev_err(&pdev->dev, "failed to allocate startup pages\n"); - goto err_pagealloc_cleanup; + dev_err(&pdev->dev, "failed to allocate init pages\n"); + goto reclaim_boot_pages; } err = mlx5_pagealloc_start(dev); if (err) { dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n"); - goto err_reclaim_pages; + goto reclaim_boot_pages; } err = mlx5_cmd_init_hca(dev); @@ -396,9 +447,12 @@ err_stop_poll: err_pagealloc_stop: mlx5_pagealloc_stop(dev); -err_reclaim_pages: +reclaim_boot_pages: mlx5_reclaim_startup_pages(dev); +err_disable_hca: + mlx5_core_disable_hca(dev); + err_pagealloc_cleanup: mlx5_pagealloc_cleanup(dev); mlx5_cmd_cleanup(dev); @@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cmd_teardown_hca(dev); mlx5_pagealloc_stop(dev); mlx5_reclaim_startup_pages(dev); + mlx5_core_disable_hca(dev); mlx5_pagealloc_cleanup(dev); mlx5_cmd_cleanup(dev); iounmap(dev->iseg); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index f0bf463..4a3e137 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -64,7 +64,7 @@ struct mlx5_query_pages_inbox { struct mlx5_query_pages_outbox { struct mlx5_outbox_hdr hdr; - u8 reserved[2]; + __be16 num_boot_pages; __be16 func_id; __be16 init_pages; __be16 num_pages; @@ -146,7 +146,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr) } static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, - s16 *pages, s16 *init_pages) + s16 *pages, s16 *init_pages, u16 *boot_pages) { struct mlx5_query_pages_inbox in; struct mlx5_query_pages_outbox out; @@ -164,8 +164,13 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, if (pages) *pages = be16_to_cpu(out.num_pages); + if (init_pages) *init_pages = be16_to_cpu(out.init_pages); + + if (boot_pages) + *boot_pages = be16_to_cpu(out.num_boot_pages); + *func_id = be16_to_cpu(out.func_id); return err; @@ -357,19 +362,22 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, queue_work(dev->priv.pg_wq, &req->work); } -int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev) +int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot) { + u16 uninitialized_var(boot_pages); s16 uninitialized_var(init_pages); u16 uninitialized_var(func_id); int err; - err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages); + err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages, + &boot_pages); if (err) return err; - mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id); - return give_pages(dev, func_id, init_pages, 0); + mlx5_core_dbg(dev, "requested %d init pages and %d boot pages for func_id 0x%x\n", + init_pages, boot_pages, func_id); + return give_pages(dev, func_id, boot ? boot_pages : init_pages, 0); } static int optimal_reclaimed_pages(void) diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 8de8d8f..737685e 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -690,6 +690,26 @@ struct mlx5_query_cq_mbox_out { __be64 pas[0]; }; +struct mlx5_enable_hca_mbox_in { + struct mlx5_inbox_hdr hdr; + u8 rsvd[8]; +}; + +struct mlx5_enable_hca_mbox_out { + struct mlx5_outbox_hdr hdr; + u8 rsvd[8]; +}; + +struct mlx5_disable_hca_mbox_in { + struct mlx5_inbox_hdr hdr; + u8 rsvd[8]; +}; + +struct mlx5_disable_hca_mbox_out { + struct mlx5_outbox_hdr hdr; + u8 rsvd[8]; +}; + struct mlx5_eq_context { u8 status; u8 ec_oi; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index f22e441..2aa258b 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -101,6 +101,8 @@ enum { MLX5_CMD_OP_QUERY_ADAPTER = 0x101, MLX5_CMD_OP_INIT_HCA = 0x102, MLX5_CMD_OP_TEARDOWN_HCA = 0x103, + MLX5_CMD_OP_ENABLE_HCA = 0x104, + MLX5_CMD_OP_DISABLE_HCA = 0x105, MLX5_CMD_OP_QUERY_PAGES = 0x107, MLX5_CMD_OP_MANAGE_PAGES = 0x108, MLX5_CMD_OP_SET_HCA_CAP = 0x109, @@ -690,7 +692,7 @@ int mlx5_pagealloc_start(struct mlx5_core_dev *dev); void mlx5_pagealloc_stop(struct mlx5_core_dev *dev); void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, s16 npages); -int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev); +int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot); int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev); void mlx5_register_debugfs(void); void mlx5_unregister_debugfs(void); -- cgit v0.10.2 From 618af3846be1d29118b00529e68971e8c95d5b72 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Tue, 16 Jul 2013 15:35:01 +0200 Subject: mlx5_core: Variable may be used uninitialized In the sq_overhead() function, if qp_typ is equal to IB_QPT_RC, size will be used uninitialized. Signed-off-by: Andi Shyti Acked-by: Eli Cohen Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 16ac54c..045f8cdb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -199,7 +199,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap, static int sq_overhead(enum ib_qp_type qp_type) { - int size; + int size = 0; switch (qp_type) { case IB_QPT_XRC_INI: -- cgit v0.10.2 From ef5ed4166ffc192434a9d7324339ed1d308fc2dc Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 18 Jul 2013 14:02:29 +0300 Subject: IB/core: Create QP1 using the pkey index which contains the default pkey Currently, QP1 is created using pkey index 0. This patch simply looks for the index containing the default pkey, rather than hard-coding pkey index 0. This change will have no effect in native mode, since QP0 and QP1 are created before the SM configures the port, so pkey table will still be the default table defined by the IB Spec, in C10-123: "If non-volatile storage is not used to hold P_Key Table contents, then if a PM (Partition Manager) is not present, and prior to PM initialization of the P_Key Table, the P_Key Table must act as if it contains a single valid entry, at P_Key_ix = 0, containing the default partition key. All other entries in the P_Key Table must be invalid." Thus, in the native mode case, the driver will find the default pkey at index 0 (so it will be no different than the hard-coding). However, in SR-IOV mode, for VFs, the pkey table may be paravirtualized, so that the VF's pkey index zero may not necessarily be mapped to the real pkey index 0. For VFs, therefore, it is important to find the virtual index which maps to the real default pkey. This commit does the following for QP1 creation: 1. Find the pkey index containing the default pkey, and use that index if found. ib_find_pkey() returns the index of the limited-membership default pkey (0x7FFF) if the full-member default pkey is not in the table. 2. If neither form of the default pkey is found, use pkey index 0 (previous behavior). Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Reviewed-by: Sean Hefty Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index dc3fd1e..4c837e6 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2663,6 +2663,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv) int ret, i; struct ib_qp_attr *attr; struct ib_qp *qp; + u16 pkey_index; attr = kmalloc(sizeof *attr, GFP_KERNEL); if (!attr) { @@ -2670,6 +2671,11 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv) return -ENOMEM; } + ret = ib_find_pkey(port_priv->device, port_priv->port_num, + IB_DEFAULT_PKEY_FULL, &pkey_index); + if (ret) + pkey_index = 0; + for (i = 0; i < IB_MAD_QPS_CORE; i++) { qp = port_priv->qp_info[i].qp; if (!qp) @@ -2680,7 +2686,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv) * one is needed for the Reset to Init transition */ attr->qp_state = IB_QPS_INIT; - attr->pkey_index = 0; + attr->pkey_index = pkey_index; attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY; ret = ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY); -- cgit v0.10.2 From 3d790a4c269aefef8f6d32efb07333bc65bd43fe Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 18 Jul 2013 14:02:31 +0300 Subject: IPoIB: Make sure child devices use valid/proper pkeys Make sure that the IB invalid pkey (0x0000 or 0x8000) isn't used for child devices. Also, make sure to always set the full membership bit for the pkey of devices created by rtnl link ops. Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index b6e049a..c6f71a8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1461,7 +1461,7 @@ static ssize_t create_child(struct device *dev, if (sscanf(buf, "%i", &pkey) != 1) return -EINVAL; - if (pkey < 0 || pkey > 0xffff) + if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000) return -EINVAL; /* diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c index 7468593..f81abe1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c @@ -119,6 +119,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev, } else child_pkey = nla_get_u16(data[IFLA_IPOIB_PKEY]); + if (child_pkey == 0 || child_pkey == 0x8000) + return -EINVAL; + + /* + * Set the full membership bit, so that we join the right + * broadcast group, etc. + */ + child_pkey |= 0x8000; + err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD); if (!err && data) -- cgit v0.10.2 From c2904141696ee19551f1553944446f23cdd5d95e Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Thu, 18 Jul 2013 14:02:32 +0300 Subject: IPoIB: Fix pkey change flow for virtualization environments IPoIB's required behaviour w.r.t to the pkey used by the device is the following: - For "parent" interfaces (e.g ib0, ib1, etc) who are created automatically as a result of hot-plug events from the IB core, the driver needs to take whatever pkey vlaue it finds in index 0, and stick to that index. - For child interfaces (e.g ib0.8001, etc) created by admin directive, the driver needs to use and stick to the value provided during its creation. In SR-IOV environment its possible for the VF probe to take place before the cloud management software provisions the suitable pkey for the VF in the paravirtualed PKEY table index 0. When this is the case, the VF IB stack will find in index 0 an invalide pkey, which is all zeros. Moreover, the cloud managment can assign the pkey value at index 0 at any time of the guest life cycle. The correct behavior for IPoIB to address these requirements for parent interfaces is to use PKEY_CHANGE event as trigger to optionally re-init the device pkey value and re-create all the relevant resources accordingly, if the value of the pkey in index 0 has changed (from invalid to valid or from valid value X to invalid value Y). This patch enhances the heavy flushing code which is triggered by pkey change event, to behave correctly for parent devices. For child devices, the code remains the same, namely chases pkey value and not index. Signed-off-by: Erez Shitrit Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 2cfa76f..196b1d1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port) return 0; } +/* + * Takes whatever value which is in pkey index 0 and updates priv->pkey + * returns 0 if the pkey value was changed. + */ +static inline int update_parent_pkey(struct ipoib_dev_priv *priv) +{ + int result; + u16 prev_pkey; + + prev_pkey = priv->pkey; + result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey); + if (result) { + ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n", + priv->port, result); + return result; + } + + priv->pkey |= 0x8000; + + if (prev_pkey != priv->pkey) { + ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n", + prev_pkey, priv->pkey); + /* + * Update the pkey in the broadcast address, while making sure to set + * the full membership bit, so that we join the right broadcast group. + */ + priv->dev->broadcast[8] = priv->pkey >> 8; + priv->dev->broadcast[9] = priv->pkey & 0xff; + return 0; + } + + return 1; +} + static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, enum ipoib_flush_level level) { struct ipoib_dev_priv *cpriv; struct net_device *dev = priv->dev; u16 new_index; + int result; mutex_lock(&priv->vlan_mutex); @@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, mutex_unlock(&priv->vlan_mutex); if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) { + /* for non-child devices must check/update the pkey value here */ + if (level == IPOIB_FLUSH_HEAVY && + !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) + update_parent_pkey(priv); ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); return; } @@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, } if (level == IPOIB_FLUSH_HEAVY) { - if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { - clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); - ipoib_ib_dev_down(dev, 0); - ipoib_ib_dev_stop(dev, 0); - if (ipoib_pkey_dev_delay_open(dev)) + /* child devices chase their origin pkey value, while non-child + * (parent) devices should always takes what present in pkey index 0 + */ + if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { + if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + ipoib_ib_dev_down(dev, 0); + ipoib_ib_dev_stop(dev, 0); + if (ipoib_pkey_dev_delay_open(dev)) + return; + } + /* restart QP only if P_Key index is changed */ + if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) && + new_index == priv->pkey_index) { + ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); return; + } + priv->pkey_index = new_index; + } else { + result = update_parent_pkey(priv); + /* restart QP only if P_Key value changed */ + if (result) { + ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n"); + return; + } } - - /* restart QP only if P_Key index is changed */ - if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) && - new_index == priv->pkey_index) { - ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); - return; - } - priv->pkey_index = new_index; } if (level == IPOIB_FLUSH_LIGHT) { -- cgit v0.10.2 From 3964acd0dbec123aa0a621973a2a0580034b4788 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 31 Jul 2013 13:53:28 -0700 Subject: mm: mempolicy: fix mbind_range() && vma_adjust() interaction vma_adjust() does vma_set_policy(vma, vma_policy(next)) and this is doubly wrong: 1. This leaks vma->vm_policy if it is not NULL and not equal to next->vm_policy. This can happen if vma_merge() expands "area", not prev (case 8). 2. This sets the wrong policy if vma_merge() joins prev and area, area is the vma the caller needs to update and it still has the old policy. Revert commit 1444f92c8498 ("mm: merging memory blocks resets mempolicy") which introduced these problems. Change mbind_range() to recheck mpol_equal() after vma_merge() to fix the problem that commit tried to address. Signed-off-by: Oleg Nesterov Acked-by: KOSAKI Motohiro Cc: Steven T Hampson Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Rik van Riel Cc: Andi Kleen Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 7431001..4baf12e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -732,7 +732,10 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (prev) { vma = prev; next = vma->vm_next; - continue; + if (mpol_equal(vma_policy(vma), new_pol)) + continue; + /* vma_merge() joined vma && vma->next, case 8 */ + goto replace; } if (vma->vm_start != vmstart) { err = split_vma(vma->vm_mm, vma, vmstart, 1); @@ -744,6 +747,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (err) goto out; } + replace: err = vma_replace_policy(vma, new_pol); if (err) goto out; diff --git a/mm/mmap.c b/mm/mmap.c index fbad7b0..1edbaa3 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -865,7 +865,7 @@ again: remove_next = 1 + (end > next->vm_end); if (next->anon_vma) anon_vma_merge(vma, next); mm->map_count--; - vma_set_policy(vma, vma_policy(next)); + mpol_put(vma_policy(next)); kmem_cache_free(vm_area_cachep, next); /* * In mprotect's case 6 (see comments on vma_merge), -- cgit v0.10.2 From 62c610460d73fcfa5637cb497c6923ef1c42b12d Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Wed, 31 Jul 2013 13:53:29 -0700 Subject: ocfs2/refcounttree: add the missing NULL check of the return value of find_or_create_page() Add the missing NULL check of the return value of find_or_create_page() in function ocfs2_duplicate_clusters_by_page(). [akpm@linux-foundation.org: fix layout, per Joel] Signed-off-by: Gu Zheng Acked-by: Joel Becker Cc: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 998b17e..9f6b96a 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -2965,6 +2965,11 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle, to = map_end & (PAGE_CACHE_SIZE - 1); page = find_or_create_page(mapping, page_index, GFP_NOFS); + if (!page) { + ret = -ENOMEM; + mlog_errno(ret); + break; + } /* * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page -- cgit v0.10.2 From d39de28c95876f8becb559d242eefe718ea1f747 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 31 Jul 2013 13:53:30 -0700 Subject: dmi_scan: add comments on dmi_present() and the loop in dmi_scan_machine() My previous refactoring in commit 79bae42d51a5 ("dmi_scan: refactor dmi_scan_machine(), {smbios,dmi}_present()") resulted in slightly tricky code (though I think it's more elegant). Explain what it's doing. Signed-off-by: Ben Hutchings Cc: Zhenzhong Duan Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index eb760a2..232fa8f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -419,6 +419,13 @@ static void __init dmi_format_ids(char *buf, size_t len) dmi_get_system_info(DMI_BIOS_DATE)); } +/* + * Check for DMI/SMBIOS headers in the system firmware image. Any + * SMBIOS header must start 16 bytes before the DMI header, so take a + * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset + * 0. If the DMI header is present, set dmi_ver accordingly (SMBIOS + * takes precedence) and return 0. Otherwise return 1. + */ static int __init dmi_present(const u8 *buf) { int smbios_ver; @@ -506,6 +513,13 @@ void __init dmi_scan_machine(void) if (p == NULL) goto error; + /* + * Iterate over all possible DMI header addresses q. + * Maintain the 32 bytes around q in buf. On the + * first iteration, substitute zero for the + * out-of-range bytes so there is no chance of falsely + * detecting an SMBIOS header. + */ memset(buf, 0, 16); for (q = p; q < p + 0x10000; q += 16) { memcpy_fromio(buf + 16, q, 16); -- cgit v0.10.2 From 5c4a97d1dabb3443da7acc309ae61c5de8494fa9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:32 -0700 Subject: MAINTAINERS: dynamic debug: Jason's not there... He must be too, umm, busy to update his own bouncing email address too. Signed-off-by: Joe Perches Acked-by: Jason Baron Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index a26b10e..d83f70f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2871,7 +2871,7 @@ F: drivers/media/usb/dvb-usb-v2/dvb_usb* F: drivers/media/usb/dvb-usb-v2/usb_urb.c DYNAMIC DEBUG -M: Jason Baron +M: Jason Baron S: Maintained F: lib/dynamic_debug.c F: include/linux/dynamic_debug.h -- cgit v0.10.2 From 4e5052948110140f1628dd986e27912b0e6b2065 Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Wed, 31 Jul 2013 13:53:33 -0700 Subject: .gitignore: ignore *.lz4 files Now that lz4 kernel compression is available, add *.lz4 to .gitignore. Signed-off-by: Markus Trippelsdorf Acked-by: Kyungsik Lee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/.gitignore b/.gitignore index 3b8b9b3..7e9932e 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ modules.builtin *.bz2 *.lzma *.xz +*.lz4 *.lzo *.patch *.gcno -- cgit v0.10.2 From f93f3c4ee48727713c3349b659adf8048fd4524b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 31 Jul 2013 13:53:34 -0700 Subject: rapidio: fix use after free in rio_unregister_scan() We're freeing the list iterator so we can't move to the next entry. Since there is only one matching mport_id, we can just break after finding it. Signed-off-by: Dan Carpenter Reviewed-by: Ryan Mallon Acked-by: Alexandre Bounine Cc: Matt Porter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index f4f30af..2e8a20c 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1715,11 +1715,13 @@ int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops) (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops)) port->nscan = NULL; - list_for_each_entry(scan, &rio_scans, node) + list_for_each_entry(scan, &rio_scans, node) { if (scan->mport_id == mport_id) { list_del(&scan->node); kfree(scan); + break; } + } mutex_unlock(&rio_mport_list_lock); -- cgit v0.10.2 From 10e84b97ed799be404836dc7f71ab47d4571265a Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 31 Jul 2013 13:53:35 -0700 Subject: mm: sched: numa: fix NUMA balancing when !SCHED_DEBUG Commit 3105b86a9fee ("mm: sched: numa: Control enabling and disabling of NUMA balancing if !SCHED_DEBUG") defined numabalancing_enabled to control the enabling and disabling of automatic NUMA balancing, but it is never used. I believe the intention was to use this in place of sched_feat_numa(NUMA). Currently, if SCHED_DEBUG is not defined, sched_feat_numa(NUMA) will never be changed from the initial "false". Signed-off-by: Dave Kleikamp Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bb456f4..9565645 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -851,7 +851,7 @@ void task_numa_fault(int node, int pages, bool migrated) { struct task_struct *p = current; - if (!sched_feat_numa(NUMA)) + if (!numabalancing_enabled) return; /* FIXME: Allocate task-specific structure for placement policy here */ @@ -5786,7 +5786,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) entity_tick(cfs_rq, se, queued); } - if (sched_feat_numa(NUMA)) + if (numabalancing_enabled) task_tick_numa(rq, curr); update_rq_runnable_avg(rq, 1); -- cgit v0.10.2 From 31a1b26f16e822577def5402ffc79cfe4aed2db9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 31 Jul 2013 13:53:36 -0700 Subject: arch/x86/platform/ce4100/ce4100.c: include reboot.h Fix the build: arch/x86/platform/ce4100/ce4100.c: In function 'x86_ce4100_early_setup': arch/x86/platform/ce4100/ce4100.c:165:2: error: 'reboot_type' undeclared (first use in this function) Reported-by: Wu Fengguang Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c index 643b8b5e..8244f5e 100644 --- a/arch/x86/platform/ce4100/ce4100.c +++ b/arch/x86/platform/ce4100/ce4100.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From ef2a2cbdda7e9d084a85846770fcc844958881f6 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Wed, 31 Jul 2013 13:53:37 -0700 Subject: mm/swap.c: clear PageActive before adding pages onto unevictable list As a result of commit 13f7f78981e4 ("mm: pagevec: defer deciding which LRU to add a page to until pagevec drain time"), pages on unevictable lists can have both of PageActive and PageUnevictable set. This is not only confusing, but also corrupts page migration and shrink_[in]active_list. This patch fixes the problem by adding ClearPageActive before adding pages into unevictable list. It also cleans up VM_BUG_ONs. Signed-off-by: Naoya Horiguchi Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: "Kirill A. Shutemov" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/swap.c b/mm/swap.c index 4a1d0d2..d3982c0 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -512,12 +512,7 @@ EXPORT_SYMBOL(__lru_cache_add); */ void lru_cache_add(struct page *page) { - if (PageActive(page)) { - VM_BUG_ON(PageUnevictable(page)); - } else if (PageUnevictable(page)) { - VM_BUG_ON(PageActive(page)); - } - + VM_BUG_ON(PageActive(page) && PageUnevictable(page)); VM_BUG_ON(PageLRU(page)); __lru_cache_add(page); } @@ -539,6 +534,7 @@ void add_page_to_unevictable_list(struct page *page) spin_lock_irq(&zone->lru_lock); lruvec = mem_cgroup_page_lruvec(page, zone); + ClearPageActive(page); SetPageUnevictable(page); SetPageLRU(page); add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE); @@ -833,7 +829,6 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, int active = PageActive(page); enum lru_list lru = page_lru(page); - VM_BUG_ON(PageUnevictable(page)); VM_BUG_ON(PageLRU(page)); SetPageLRU(page); -- cgit v0.10.2 From e180cf806a93ea1abbce47b245d25204ff557ce9 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 31 Jul 2013 13:53:39 -0700 Subject: thp, mm: avoid PageUnevictable on active/inactive lru lists active/inactive lru lists can contain unevicable pages (i.e. ramfs pages that have been placed on the LRU lists when first allocated), but these pages must not have PageUnevictable set - otherwise shrink_[in]active_list goes crazy: kernel BUG at /home/space/kas/git/public/linux-next/mm/vmscan.c:1122! 1090 static unsigned long isolate_lru_pages(unsigned long nr_to_scan, 1091 struct lruvec *lruvec, struct list_head *dst, 1092 unsigned long *nr_scanned, struct scan_control *sc, 1093 isolate_mode_t mode, enum lru_list lru) 1094 { ... 1108 switch (__isolate_lru_page(page, mode)) { 1109 case 0: ... 1116 case -EBUSY: ... 1121 default: 1122 BUG(); 1123 } 1124 } ... 1130 } __isolate_lru_page() returns EINVAL for PageUnevictable(page). For lru_add_page_tail(), it means we should not set PageUnevictable() for tail pages unless we're sure that it will go to LRU_UNEVICTABLE. Let's just copy PG_active and PG_unevictable from head page in __split_huge_page_refcount(), it will simplify lru_add_page_tail(). This will fix one more bug in lru_add_page_tail(): if page_evictable(page_tail) is false and PageLRU(page) is true, page_tail will go to the same lru as page, but nobody cares to sync page_tail active/inactive state with page. So we can end up with inactive page on active lru. The patch will fix it as well since we copy PG_active from head page. Signed-off-by: Kirill A. Shutemov Acked-by: Dave Hansen Cc: Naoya Horiguchi Cc: Mel Gorman Cc: KOSAKI Motohiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 243e710..a92012a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1620,7 +1620,9 @@ static void __split_huge_page_refcount(struct page *page, ((1L << PG_referenced) | (1L << PG_swapbacked) | (1L << PG_mlocked) | - (1L << PG_uptodate))); + (1L << PG_uptodate) | + (1L << PG_active) | + (1L << PG_unevictable))); page_tail->flags |= (1L << PG_dirty); /* clear PageTail before overwriting first_page */ diff --git a/mm/swap.c b/mm/swap.c index d3982c0..62b78a6 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -770,8 +770,6 @@ EXPORT_SYMBOL(__pagevec_release); void lru_add_page_tail(struct page *page, struct page *page_tail, struct lruvec *lruvec, struct list_head *list) { - int uninitialized_var(active); - enum lru_list lru; const int file = 0; VM_BUG_ON(!PageHead(page)); @@ -783,20 +781,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, if (!list) SetPageLRU(page_tail); - if (page_evictable(page_tail)) { - if (PageActive(page)) { - SetPageActive(page_tail); - active = 1; - lru = LRU_ACTIVE_ANON; - } else { - active = 0; - lru = LRU_INACTIVE_ANON; - } - } else { - SetPageUnevictable(page_tail); - lru = LRU_UNEVICTABLE; - } - if (likely(PageLRU(page))) list_add_tail(&page_tail->lru, &page->lru); else if (list) { @@ -812,13 +796,13 @@ void lru_add_page_tail(struct page *page, struct page *page_tail, * Use the standard add function to put page_tail on the list, * but then correct its position so they all end up in order. */ - add_page_to_lru_list(page_tail, lruvec, lru); + add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail)); list_head = page_tail->lru.prev; list_move_tail(&page_tail->lru, list_head); } if (!PageUnevictable(page)) - update_page_reclaim_stat(lruvec, file, active); + update_page_reclaim_stat(lruvec, file, PageActive(page_tail)); } #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -- cgit v0.10.2 From 9d8c5b5284e4a0167c5f7b1193692492358b8700 Mon Sep 17 00:00:00 2001 From: Heesub Shin Date: Wed, 31 Jul 2013 13:53:40 -0700 Subject: mm: zbud: fix condition check on allocation size zbud_alloc() incorrectly verifies the size of allocation limit. It should deny the allocation request greater than (PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE), not (PAGE_SIZE - ZHDR_SIZE_ALIGNED) which has no remaining spaces for its buddy. There is no point in spending the entire zbud page storing only a single page, since we don't have any benefits. Signed-off-by: Heesub Shin Acked-by: Seth Jennings Cc: Bob Liu Cc: Dongjun Shin Cc: Sunae Seo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/zbud.c b/mm/zbud.c index 9bb4710..ad1e781 100644 --- a/mm/zbud.c +++ b/mm/zbud.c @@ -257,7 +257,7 @@ int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp, if (size <= 0 || gfp & __GFP_HIGHMEM) return -EINVAL; - if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED) + if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE) return -ENOSPC; chunks = size_to_chunks(size); spin_lock(&pool->lock); -- cgit v0.10.2 From b99b94b52339dc186810e29f1f6472d86c42d2d9 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 31 Jul 2013 13:53:41 -0700 Subject: drivers/rtc/rtc-twl.c: fix: rtcX/wakealarm attribute isn't created The device_init_wakeup() should be called before rtc_device_register(). Otherwise, sysfs "sys/class/rtc/rtcX/wakealarm" attribute will not be seen from User space. Signed-off-by: Grygorii Strashko Cc: Kevin Hilman Cc: Tony Lindgren Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 02faf3c..c2e80d7 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -524,6 +524,8 @@ static int twl_rtc_probe(struct platform_device *pdev) if (ret < 0) goto out1; + device_init_wakeup(&pdev->dev, 1); + rtc = rtc_device_register(pdev->name, &pdev->dev, &twl_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { @@ -542,7 +544,6 @@ static int twl_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); - device_init_wakeup(&pdev->dev, 1); return 0; out2: -- cgit v0.10.2 From b9ee979e9d770dc10f94936ef6ff9efddc23c911 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:42 -0700 Subject: printk: move to separate directory for easier modification Make it easier to break up printk into bite-sized chunks. Remove printk path/filename from comment. Signed-off-by: Joe Perches Cc: Samuel Thibault Cc: Ming Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index cbfdf54..fe397f9 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -84,7 +84,7 @@ X!Iinclude/linux/kobject.h Kernel utility functions !Iinclude/linux/kernel.h -!Ekernel/printk.c +!Ekernel/printk/printk.c !Ekernel/panic.c !Ekernel/sys.c !Ekernel/rcupdate.c diff --git a/kernel/Makefile b/kernel/Makefile index 470839d..35ef118 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y = fork.o exec_domain.o panic.o printk.o \ +obj-y = fork.o exec_domain.o panic.o \ cpu.o exit.o itimer.o time.o softirq.o resource.o \ sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ @@ -24,6 +24,7 @@ endif obj-y += sched/ obj-y += power/ +obj-y += printk/ obj-y += cpu/ obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o diff --git a/kernel/printk.c b/kernel/printk.c deleted file mode 100644 index 69b0890..0000000 --- a/kernel/printk.c +++ /dev/null @@ -1,2924 +0,0 @@ -/* - * linux/kernel/printk.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Modified to make sys_syslog() more flexible: added commands to - * return the last 4k of kernel messages, regardless of whether - * they've been read or not. Added option to suppress kernel printk's - * to the console. Added hook for sending the console messages - * elsewhere, in preparation for a serial line console (someday). - * Ted Ts'o, 2/11/93. - * Modified for sysctl support, 1/8/97, Chris Horn. - * Fixed SMP synchronization, 08/08/99, Manfred Spraul - * manfred@colorfullife.com - * Rewrote bits to get rid of console_lock - * 01Mar01 Andrew Morton - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For in_interrupt() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define CREATE_TRACE_POINTS -#include - -/* printk's without a loglevel use this.. */ -#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL - -/* We show everything that is MORE important than this.. */ -#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ -#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ - -int console_printk[4] = { - DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ - DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ - MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ - DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ -}; - -/* - * Low level drivers may need that to know if they can schedule in - * their unblank() callback or not. So let's export it. - */ -int oops_in_progress; -EXPORT_SYMBOL(oops_in_progress); - -/* - * console_sem protects the console_drivers list, and also - * provides serialisation for access to the entire console - * driver system. - */ -static DEFINE_SEMAPHORE(console_sem); -struct console *console_drivers; -EXPORT_SYMBOL_GPL(console_drivers); - -#ifdef CONFIG_LOCKDEP -static struct lockdep_map console_lock_dep_map = { - .name = "console_lock" -}; -#endif - -/* - * This is used for debugging the mess that is the VT code by - * keeping track if we have the console semaphore held. It's - * definitely not the perfect debug tool (we don't know if _WE_ - * hold it are racing, but it helps tracking those weird code - * path in the console code where we end up in places I want - * locked without the console sempahore held - */ -static int console_locked, console_suspended; - -/* - * If exclusive_console is non-NULL then only this console is to be printed to. - */ -static struct console *exclusive_console; - -/* - * Array of consoles built from command line options (console=) - */ -struct console_cmdline -{ - char name[8]; /* Name of the driver */ - int index; /* Minor dev. to use */ - char *options; /* Options for the driver */ -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - char *brl_options; /* Options for braille driver */ -#endif -}; - -#define MAX_CMDLINECONSOLES 8 - -static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; -static int selected_console = -1; -static int preferred_console = -1; -int console_set_on_cmdline; -EXPORT_SYMBOL(console_set_on_cmdline); - -/* Flag: console code may call schedule() */ -static int console_may_schedule; - -/* - * The printk log buffer consists of a chain of concatenated variable - * length records. Every record starts with a record header, containing - * the overall length of the record. - * - * The heads to the first and last entry in the buffer, as well as the - * sequence numbers of these both entries are maintained when messages - * are stored.. - * - * If the heads indicate available messages, the length in the header - * tells the start next message. A length == 0 for the next message - * indicates a wrap-around to the beginning of the buffer. - * - * Every record carries the monotonic timestamp in microseconds, as well as - * the standard userspace syslog level and syslog facility. The usual - * kernel messages use LOG_KERN; userspace-injected messages always carry - * a matching syslog facility, by default LOG_USER. The origin of every - * message can be reliably determined that way. - * - * The human readable log message directly follows the message header. The - * length of the message text is stored in the header, the stored message - * is not terminated. - * - * Optionally, a message can carry a dictionary of properties (key/value pairs), - * to provide userspace with a machine-readable message context. - * - * Examples for well-defined, commonly used property names are: - * DEVICE=b12:8 device identifier - * b12:8 block dev_t - * c127:3 char dev_t - * n8 netdev ifindex - * +sound:card0 subsystem:devname - * SUBSYSTEM=pci driver-core subsystem name - * - * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value - * follows directly after a '=' character. Every property is terminated by - * a '\0' character. The last property is not terminated. - * - * Example of a message structure: - * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec - * 0008 34 00 record is 52 bytes long - * 000a 0b 00 text is 11 bytes long - * 000c 1f 00 dictionary is 23 bytes long - * 000e 03 00 LOG_KERN (facility) LOG_ERR (level) - * 0010 69 74 27 73 20 61 20 6c "it's a l" - * 69 6e 65 "ine" - * 001b 44 45 56 49 43 "DEVIC" - * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D" - * 52 49 56 45 52 3d 62 75 "RIVER=bu" - * 67 "g" - * 0032 00 00 00 padding to next message header - * - * The 'struct log' buffer header must never be directly exported to - * userspace, it is a kernel-private implementation detail that might - * need to be changed in the future, when the requirements change. - * - * /dev/kmsg exports the structured data in the following line format: - * "level,sequnum,timestamp;\n" - * - * The optional key/value pairs are attached as continuation lines starting - * with a space character and terminated by a newline. All possible - * non-prinatable characters are escaped in the "\xff" notation. - * - * Users of the export format should ignore possible additional values - * separated by ',', and find the message after the ';' character. - */ - -enum log_flags { - LOG_NOCONS = 1, /* already flushed, do not print to console */ - LOG_NEWLINE = 2, /* text ended with a newline */ - LOG_PREFIX = 4, /* text started with a prefix */ - LOG_CONT = 8, /* text is a fragment of a continuation line */ -}; - -struct log { - u64 ts_nsec; /* timestamp in nanoseconds */ - u16 len; /* length of entire record */ - u16 text_len; /* length of text buffer */ - u16 dict_len; /* length of dictionary buffer */ - u8 facility; /* syslog facility */ - u8 flags:5; /* internal record flags */ - u8 level:3; /* syslog level */ -}; - -/* - * The logbuf_lock protects kmsg buffer, indices, counters. It is also - * used in interesting ways to provide interlocking in console_unlock(); - */ -static DEFINE_RAW_SPINLOCK(logbuf_lock); - -#ifdef CONFIG_PRINTK -DECLARE_WAIT_QUEUE_HEAD(log_wait); -/* the next printk record to read by syslog(READ) or /proc/kmsg */ -static u64 syslog_seq; -static u32 syslog_idx; -static enum log_flags syslog_prev; -static size_t syslog_partial; - -/* index and sequence number of the first record stored in the buffer */ -static u64 log_first_seq; -static u32 log_first_idx; - -/* index and sequence number of the next record to store in the buffer */ -static u64 log_next_seq; -static u32 log_next_idx; - -/* the next printk record to write to the console */ -static u64 console_seq; -static u32 console_idx; -static enum log_flags console_prev; - -/* the next printk record to read after the last 'clear' command */ -static u64 clear_seq; -static u32 clear_idx; - -#define PREFIX_MAX 32 -#define LOG_LINE_MAX 1024 - PREFIX_MAX - -/* record buffer */ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) -#define LOG_ALIGN 4 -#else -#define LOG_ALIGN __alignof__(struct log) -#endif -#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) -static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); -static char *log_buf = __log_buf; -static u32 log_buf_len = __LOG_BUF_LEN; - -/* cpu currently holding logbuf_lock */ -static volatile unsigned int logbuf_cpu = UINT_MAX; - -/* human readable text of the record */ -static char *log_text(const struct log *msg) -{ - return (char *)msg + sizeof(struct log); -} - -/* optional key/value pair dictionary attached to the record */ -static char *log_dict(const struct log *msg) -{ - return (char *)msg + sizeof(struct log) + msg->text_len; -} - -/* get record by index; idx must point to valid msg */ -static struct log *log_from_idx(u32 idx) -{ - struct log *msg = (struct log *)(log_buf + idx); - - /* - * A length == 0 record is the end of buffer marker. Wrap around and - * read the message at the start of the buffer. - */ - if (!msg->len) - return (struct log *)log_buf; - return msg; -} - -/* get next record; idx must point to valid msg */ -static u32 log_next(u32 idx) -{ - struct log *msg = (struct log *)(log_buf + idx); - - /* length == 0 indicates the end of the buffer; wrap */ - /* - * A length == 0 record is the end of buffer marker. Wrap around and - * read the message at the start of the buffer as *this* one, and - * return the one after that. - */ - if (!msg->len) { - msg = (struct log *)log_buf; - return msg->len; - } - return idx + msg->len; -} - -/* insert record into the buffer, discard old ones, update heads */ -static void log_store(int facility, int level, - enum log_flags flags, u64 ts_nsec, - const char *dict, u16 dict_len, - const char *text, u16 text_len) -{ - struct log *msg; - u32 size, pad_len; - - /* number of '\0' padding bytes to next message */ - size = sizeof(struct log) + text_len + dict_len; - pad_len = (-size) & (LOG_ALIGN - 1); - size += pad_len; - - while (log_first_seq < log_next_seq) { - u32 free; - - if (log_next_idx > log_first_idx) - free = max(log_buf_len - log_next_idx, log_first_idx); - else - free = log_first_idx - log_next_idx; - - if (free > size + sizeof(struct log)) - break; - - /* drop old messages until we have enough contiuous space */ - log_first_idx = log_next(log_first_idx); - log_first_seq++; - } - - if (log_next_idx + size + sizeof(struct log) >= log_buf_len) { - /* - * This message + an additional empty header does not fit - * at the end of the buffer. Add an empty header with len == 0 - * to signify a wrap around. - */ - memset(log_buf + log_next_idx, 0, sizeof(struct log)); - log_next_idx = 0; - } - - /* fill message */ - msg = (struct log *)(log_buf + log_next_idx); - memcpy(log_text(msg), text, text_len); - msg->text_len = text_len; - memcpy(log_dict(msg), dict, dict_len); - msg->dict_len = dict_len; - msg->facility = facility; - msg->level = level & 7; - msg->flags = flags & 0x1f; - if (ts_nsec > 0) - msg->ts_nsec = ts_nsec; - else - msg->ts_nsec = local_clock(); - memset(log_dict(msg) + dict_len, 0, pad_len); - msg->len = sizeof(struct log) + text_len + dict_len + pad_len; - - /* insert message */ - log_next_idx += msg->len; - log_next_seq++; -} - -#ifdef CONFIG_SECURITY_DMESG_RESTRICT -int dmesg_restrict = 1; -#else -int dmesg_restrict; -#endif - -static int syslog_action_restricted(int type) -{ - if (dmesg_restrict) - return 1; - /* - * Unless restricted, we allow "read all" and "get buffer size" - * for everybody. - */ - return type != SYSLOG_ACTION_READ_ALL && - type != SYSLOG_ACTION_SIZE_BUFFER; -} - -static int check_syslog_permissions(int type, bool from_file) -{ - /* - * If this is from /proc/kmsg and we've already opened it, then we've - * already done the capabilities checks at open time. - */ - if (from_file && type != SYSLOG_ACTION_OPEN) - return 0; - - if (syslog_action_restricted(type)) { - if (capable(CAP_SYSLOG)) - return 0; - /* - * For historical reasons, accept CAP_SYS_ADMIN too, with - * a warning. - */ - if (capable(CAP_SYS_ADMIN)) { - pr_warn_once("%s (%d): Attempt to access syslog with " - "CAP_SYS_ADMIN but no CAP_SYSLOG " - "(deprecated).\n", - current->comm, task_pid_nr(current)); - return 0; - } - return -EPERM; - } - return security_syslog(type); -} - - -/* /dev/kmsg - userspace message inject/listen interface */ -struct devkmsg_user { - u64 seq; - u32 idx; - enum log_flags prev; - struct mutex lock; - char buf[8192]; -}; - -static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv, - unsigned long count, loff_t pos) -{ - char *buf, *line; - int i; - int level = default_message_loglevel; - int facility = 1; /* LOG_USER */ - size_t len = iov_length(iv, count); - ssize_t ret = len; - - if (len > LOG_LINE_MAX) - return -EINVAL; - buf = kmalloc(len+1, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - line = buf; - for (i = 0; i < count; i++) { - if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) { - ret = -EFAULT; - goto out; - } - line += iv[i].iov_len; - } - - /* - * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace - * the decimal value represents 32bit, the lower 3 bit are the log - * level, the rest are the log facility. - * - * If no prefix or no userspace facility is specified, we - * enforce LOG_USER, to be able to reliably distinguish - * kernel-generated messages from userspace-injected ones. - */ - line = buf; - if (line[0] == '<') { - char *endp = NULL; - - i = simple_strtoul(line+1, &endp, 10); - if (endp && endp[0] == '>') { - level = i & 7; - if (i >> 3) - facility = i >> 3; - endp++; - len -= endp - line; - line = endp; - } - } - line[len] = '\0'; - - printk_emit(facility, level, NULL, 0, "%s", line); -out: - kfree(buf); - return ret; -} - -static ssize_t devkmsg_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct devkmsg_user *user = file->private_data; - struct log *msg; - u64 ts_usec; - size_t i; - char cont = '-'; - size_t len; - ssize_t ret; - - if (!user) - return -EBADF; - - ret = mutex_lock_interruptible(&user->lock); - if (ret) - return ret; - raw_spin_lock_irq(&logbuf_lock); - while (user->seq == log_next_seq) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - raw_spin_unlock_irq(&logbuf_lock); - goto out; - } - - raw_spin_unlock_irq(&logbuf_lock); - ret = wait_event_interruptible(log_wait, - user->seq != log_next_seq); - if (ret) - goto out; - raw_spin_lock_irq(&logbuf_lock); - } - - if (user->seq < log_first_seq) { - /* our last seen message is gone, return error and reset */ - user->idx = log_first_idx; - user->seq = log_first_seq; - ret = -EPIPE; - raw_spin_unlock_irq(&logbuf_lock); - goto out; - } - - msg = log_from_idx(user->idx); - ts_usec = msg->ts_nsec; - do_div(ts_usec, 1000); - - /* - * If we couldn't merge continuation line fragments during the print, - * export the stored flags to allow an optional external merge of the - * records. Merging the records isn't always neccessarily correct, like - * when we hit a race during printing. In most cases though, it produces - * better readable output. 'c' in the record flags mark the first - * fragment of a line, '+' the following. - */ - if (msg->flags & LOG_CONT && !(user->prev & LOG_CONT)) - cont = 'c'; - else if ((msg->flags & LOG_CONT) || - ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))) - cont = '+'; - - len = sprintf(user->buf, "%u,%llu,%llu,%c;", - (msg->facility << 3) | msg->level, - user->seq, ts_usec, cont); - user->prev = msg->flags; - - /* escape non-printable characters */ - for (i = 0; i < msg->text_len; i++) { - unsigned char c = log_text(msg)[i]; - - if (c < ' ' || c >= 127 || c == '\\') - len += sprintf(user->buf + len, "\\x%02x", c); - else - user->buf[len++] = c; - } - user->buf[len++] = '\n'; - - if (msg->dict_len) { - bool line = true; - - for (i = 0; i < msg->dict_len; i++) { - unsigned char c = log_dict(msg)[i]; - - if (line) { - user->buf[len++] = ' '; - line = false; - } - - if (c == '\0') { - user->buf[len++] = '\n'; - line = true; - continue; - } - - if (c < ' ' || c >= 127 || c == '\\') { - len += sprintf(user->buf + len, "\\x%02x", c); - continue; - } - - user->buf[len++] = c; - } - user->buf[len++] = '\n'; - } - - user->idx = log_next(user->idx); - user->seq++; - raw_spin_unlock_irq(&logbuf_lock); - - if (len > count) { - ret = -EINVAL; - goto out; - } - - if (copy_to_user(buf, user->buf, len)) { - ret = -EFAULT; - goto out; - } - ret = len; -out: - mutex_unlock(&user->lock); - return ret; -} - -static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) -{ - struct devkmsg_user *user = file->private_data; - loff_t ret = 0; - - if (!user) - return -EBADF; - if (offset) - return -ESPIPE; - - raw_spin_lock_irq(&logbuf_lock); - switch (whence) { - case SEEK_SET: - /* the first record */ - user->idx = log_first_idx; - user->seq = log_first_seq; - break; - case SEEK_DATA: - /* - * The first record after the last SYSLOG_ACTION_CLEAR, - * like issued by 'dmesg -c'. Reading /dev/kmsg itself - * changes no global state, and does not clear anything. - */ - user->idx = clear_idx; - user->seq = clear_seq; - break; - case SEEK_END: - /* after the last record */ - user->idx = log_next_idx; - user->seq = log_next_seq; - break; - default: - ret = -EINVAL; - } - raw_spin_unlock_irq(&logbuf_lock); - return ret; -} - -static unsigned int devkmsg_poll(struct file *file, poll_table *wait) -{ - struct devkmsg_user *user = file->private_data; - int ret = 0; - - if (!user) - return POLLERR|POLLNVAL; - - poll_wait(file, &log_wait, wait); - - raw_spin_lock_irq(&logbuf_lock); - if (user->seq < log_next_seq) { - /* return error when data has vanished underneath us */ - if (user->seq < log_first_seq) - ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; - else - ret = POLLIN|POLLRDNORM; - } - raw_spin_unlock_irq(&logbuf_lock); - - return ret; -} - -static int devkmsg_open(struct inode *inode, struct file *file) -{ - struct devkmsg_user *user; - int err; - - /* write-only does not need any file context */ - if ((file->f_flags & O_ACCMODE) == O_WRONLY) - return 0; - - err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL, - SYSLOG_FROM_READER); - if (err) - return err; - - user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL); - if (!user) - return -ENOMEM; - - mutex_init(&user->lock); - - raw_spin_lock_irq(&logbuf_lock); - user->idx = log_first_idx; - user->seq = log_first_seq; - raw_spin_unlock_irq(&logbuf_lock); - - file->private_data = user; - return 0; -} - -static int devkmsg_release(struct inode *inode, struct file *file) -{ - struct devkmsg_user *user = file->private_data; - - if (!user) - return 0; - - mutex_destroy(&user->lock); - kfree(user); - return 0; -} - -const struct file_operations kmsg_fops = { - .open = devkmsg_open, - .read = devkmsg_read, - .aio_write = devkmsg_writev, - .llseek = devkmsg_llseek, - .poll = devkmsg_poll, - .release = devkmsg_release, -}; - -#ifdef CONFIG_KEXEC -/* - * This appends the listed symbols to /proc/vmcoreinfo - * - * /proc/vmcoreinfo is used by various utiilties, like crash and makedumpfile to - * obtain access to symbols that are otherwise very difficult to locate. These - * symbols are specifically used so that utilities can access and extract the - * dmesg log from a vmcore file after a crash. - */ -void log_buf_kexec_setup(void) -{ - VMCOREINFO_SYMBOL(log_buf); - VMCOREINFO_SYMBOL(log_buf_len); - VMCOREINFO_SYMBOL(log_first_idx); - VMCOREINFO_SYMBOL(log_next_idx); - /* - * Export struct log size and field offsets. User space tools can - * parse it and detect any changes to structure down the line. - */ - VMCOREINFO_STRUCT_SIZE(log); - VMCOREINFO_OFFSET(log, ts_nsec); - VMCOREINFO_OFFSET(log, len); - VMCOREINFO_OFFSET(log, text_len); - VMCOREINFO_OFFSET(log, dict_len); -} -#endif - -/* requested log_buf_len from kernel cmdline */ -static unsigned long __initdata new_log_buf_len; - -/* save requested log_buf_len since it's too early to process it */ -static int __init log_buf_len_setup(char *str) -{ - unsigned size = memparse(str, &str); - - if (size) - size = roundup_pow_of_two(size); - if (size > log_buf_len) - new_log_buf_len = size; - - return 0; -} -early_param("log_buf_len", log_buf_len_setup); - -void __init setup_log_buf(int early) -{ - unsigned long flags; - char *new_log_buf; - int free; - - if (!new_log_buf_len) - return; - - if (early) { - unsigned long mem; - - mem = memblock_alloc(new_log_buf_len, PAGE_SIZE); - if (!mem) - return; - new_log_buf = __va(mem); - } else { - new_log_buf = alloc_bootmem_nopanic(new_log_buf_len); - } - - if (unlikely(!new_log_buf)) { - pr_err("log_buf_len: %ld bytes not available\n", - new_log_buf_len); - return; - } - - raw_spin_lock_irqsave(&logbuf_lock, flags); - log_buf_len = new_log_buf_len; - log_buf = new_log_buf; - new_log_buf_len = 0; - free = __LOG_BUF_LEN - log_next_idx; - memcpy(log_buf, __log_buf, __LOG_BUF_LEN); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - pr_info("log_buf_len: %d\n", log_buf_len); - pr_info("early log buf free: %d(%d%%)\n", - free, (free * 100) / __LOG_BUF_LEN); -} - -static bool __read_mostly ignore_loglevel; - -static int __init ignore_loglevel_setup(char *str) -{ - ignore_loglevel = 1; - printk(KERN_INFO "debug: ignoring loglevel setting.\n"); - - return 0; -} - -early_param("ignore_loglevel", ignore_loglevel_setup); -module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to" - "print all kernel messages to the console."); - -#ifdef CONFIG_BOOT_PRINTK_DELAY - -static int boot_delay; /* msecs delay after each printk during bootup */ -static unsigned long long loops_per_msec; /* based on boot_delay */ - -static int __init boot_delay_setup(char *str) -{ - unsigned long lpj; - - lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ - loops_per_msec = (unsigned long long)lpj / 1000 * HZ; - - get_option(&str, &boot_delay); - if (boot_delay > 10 * 1000) - boot_delay = 0; - - pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, " - "HZ: %d, loops_per_msec: %llu\n", - boot_delay, preset_lpj, lpj, HZ, loops_per_msec); - return 1; -} -__setup("boot_delay=", boot_delay_setup); - -static void boot_delay_msec(int level) -{ - unsigned long long k; - unsigned long timeout; - - if ((boot_delay == 0 || system_state != SYSTEM_BOOTING) - || (level >= console_loglevel && !ignore_loglevel)) { - return; - } - - k = (unsigned long long)loops_per_msec * boot_delay; - - timeout = jiffies + msecs_to_jiffies(boot_delay); - while (k) { - k--; - cpu_relax(); - /* - * use (volatile) jiffies to prevent - * compiler reduction; loop termination via jiffies - * is secondary and may or may not happen. - */ - if (time_after(jiffies, timeout)) - break; - touch_nmi_watchdog(); - } -} -#else -static inline void boot_delay_msec(int level) -{ -} -#endif - -#if defined(CONFIG_PRINTK_TIME) -static bool printk_time = 1; -#else -static bool printk_time; -#endif -module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); - -static size_t print_time(u64 ts, char *buf) -{ - unsigned long rem_nsec; - - if (!printk_time) - return 0; - - rem_nsec = do_div(ts, 1000000000); - - if (!buf) - return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); - - return sprintf(buf, "[%5lu.%06lu] ", - (unsigned long)ts, rem_nsec / 1000); -} - -static size_t print_prefix(const struct log *msg, bool syslog, char *buf) -{ - size_t len = 0; - unsigned int prefix = (msg->facility << 3) | msg->level; - - if (syslog) { - if (buf) { - len += sprintf(buf, "<%u>", prefix); - } else { - len += 3; - if (prefix > 999) - len += 3; - else if (prefix > 99) - len += 2; - else if (prefix > 9) - len++; - } - } - - len += print_time(msg->ts_nsec, buf ? buf + len : NULL); - return len; -} - -static size_t msg_print_text(const struct log *msg, enum log_flags prev, - bool syslog, char *buf, size_t size) -{ - const char *text = log_text(msg); - size_t text_size = msg->text_len; - bool prefix = true; - bool newline = true; - size_t len = 0; - - if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) - prefix = false; - - if (msg->flags & LOG_CONT) { - if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) - prefix = false; - - if (!(msg->flags & LOG_NEWLINE)) - newline = false; - } - - do { - const char *next = memchr(text, '\n', text_size); - size_t text_len; - - if (next) { - text_len = next - text; - next++; - text_size -= next - text; - } else { - text_len = text_size; - } - - if (buf) { - if (print_prefix(msg, syslog, NULL) + - text_len + 1 >= size - len) - break; - - if (prefix) - len += print_prefix(msg, syslog, buf + len); - memcpy(buf + len, text, text_len); - len += text_len; - if (next || newline) - buf[len++] = '\n'; - } else { - /* SYSLOG_ACTION_* buffer size only calculation */ - if (prefix) - len += print_prefix(msg, syslog, NULL); - len += text_len; - if (next || newline) - len++; - } - - prefix = true; - text = next; - } while (text); - - return len; -} - -static int syslog_print(char __user *buf, int size) -{ - char *text; - struct log *msg; - int len = 0; - - text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); - if (!text) - return -ENOMEM; - - while (size > 0) { - size_t n; - size_t skip; - - raw_spin_lock_irq(&logbuf_lock); - if (syslog_seq < log_first_seq) { - /* messages are gone, move to first one */ - syslog_seq = log_first_seq; - syslog_idx = log_first_idx; - syslog_prev = 0; - syslog_partial = 0; - } - if (syslog_seq == log_next_seq) { - raw_spin_unlock_irq(&logbuf_lock); - break; - } - - skip = syslog_partial; - msg = log_from_idx(syslog_idx); - n = msg_print_text(msg, syslog_prev, true, text, - LOG_LINE_MAX + PREFIX_MAX); - if (n - syslog_partial <= size) { - /* message fits into buffer, move forward */ - syslog_idx = log_next(syslog_idx); - syslog_seq++; - syslog_prev = msg->flags; - n -= syslog_partial; - syslog_partial = 0; - } else if (!len){ - /* partial read(), remember position */ - n = size; - syslog_partial += n; - } else - n = 0; - raw_spin_unlock_irq(&logbuf_lock); - - if (!n) - break; - - if (copy_to_user(buf, text + skip, n)) { - if (!len) - len = -EFAULT; - break; - } - - len += n; - size -= n; - buf += n; - } - - kfree(text); - return len; -} - -static int syslog_print_all(char __user *buf, int size, bool clear) -{ - char *text; - int len = 0; - - text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); - if (!text) - return -ENOMEM; - - raw_spin_lock_irq(&logbuf_lock); - if (buf) { - u64 next_seq; - u64 seq; - u32 idx; - enum log_flags prev; - - if (clear_seq < log_first_seq) { - /* messages are gone, move to first available one */ - clear_seq = log_first_seq; - clear_idx = log_first_idx; - } - - /* - * Find first record that fits, including all following records, - * into the user-provided buffer for this dump. - */ - seq = clear_seq; - idx = clear_idx; - prev = 0; - while (seq < log_next_seq) { - struct log *msg = log_from_idx(idx); - - len += msg_print_text(msg, prev, true, NULL, 0); - prev = msg->flags; - idx = log_next(idx); - seq++; - } - - /* move first record forward until length fits into the buffer */ - seq = clear_seq; - idx = clear_idx; - prev = 0; - while (len > size && seq < log_next_seq) { - struct log *msg = log_from_idx(idx); - - len -= msg_print_text(msg, prev, true, NULL, 0); - prev = msg->flags; - idx = log_next(idx); - seq++; - } - - /* last message fitting into this dump */ - next_seq = log_next_seq; - - len = 0; - prev = 0; - while (len >= 0 && seq < next_seq) { - struct log *msg = log_from_idx(idx); - int textlen; - - textlen = msg_print_text(msg, prev, true, text, - LOG_LINE_MAX + PREFIX_MAX); - if (textlen < 0) { - len = textlen; - break; - } - idx = log_next(idx); - seq++; - prev = msg->flags; - - raw_spin_unlock_irq(&logbuf_lock); - if (copy_to_user(buf + len, text, textlen)) - len = -EFAULT; - else - len += textlen; - raw_spin_lock_irq(&logbuf_lock); - - if (seq < log_first_seq) { - /* messages are gone, move to next one */ - seq = log_first_seq; - idx = log_first_idx; - prev = 0; - } - } - } - - if (clear) { - clear_seq = log_next_seq; - clear_idx = log_next_idx; - } - raw_spin_unlock_irq(&logbuf_lock); - - kfree(text); - return len; -} - -int do_syslog(int type, char __user *buf, int len, bool from_file) -{ - bool clear = false; - static int saved_console_loglevel = -1; - int error; - - error = check_syslog_permissions(type, from_file); - if (error) - goto out; - - error = security_syslog(type); - if (error) - return error; - - switch (type) { - case SYSLOG_ACTION_CLOSE: /* Close log */ - break; - case SYSLOG_ACTION_OPEN: /* Open log */ - break; - case SYSLOG_ACTION_READ: /* Read from log */ - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - if (!access_ok(VERIFY_WRITE, buf, len)) { - error = -EFAULT; - goto out; - } - error = wait_event_interruptible(log_wait, - syslog_seq != log_next_seq); - if (error) - goto out; - error = syslog_print(buf, len); - break; - /* Read/clear last kernel messages */ - case SYSLOG_ACTION_READ_CLEAR: - clear = true; - /* FALL THRU */ - /* Read last kernel messages */ - case SYSLOG_ACTION_READ_ALL: - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - if (!access_ok(VERIFY_WRITE, buf, len)) { - error = -EFAULT; - goto out; - } - error = syslog_print_all(buf, len, clear); - break; - /* Clear ring buffer */ - case SYSLOG_ACTION_CLEAR: - syslog_print_all(NULL, 0, true); - break; - /* Disable logging to console */ - case SYSLOG_ACTION_CONSOLE_OFF: - if (saved_console_loglevel == -1) - saved_console_loglevel = console_loglevel; - console_loglevel = minimum_console_loglevel; - break; - /* Enable logging to console */ - case SYSLOG_ACTION_CONSOLE_ON: - if (saved_console_loglevel != -1) { - console_loglevel = saved_console_loglevel; - saved_console_loglevel = -1; - } - break; - /* Set level of messages printed to console */ - case SYSLOG_ACTION_CONSOLE_LEVEL: - error = -EINVAL; - if (len < 1 || len > 8) - goto out; - if (len < minimum_console_loglevel) - len = minimum_console_loglevel; - console_loglevel = len; - /* Implicitly re-enable logging to console */ - saved_console_loglevel = -1; - error = 0; - break; - /* Number of chars in the log buffer */ - case SYSLOG_ACTION_SIZE_UNREAD: - raw_spin_lock_irq(&logbuf_lock); - if (syslog_seq < log_first_seq) { - /* messages are gone, move to first one */ - syslog_seq = log_first_seq; - syslog_idx = log_first_idx; - syslog_prev = 0; - syslog_partial = 0; - } - if (from_file) { - /* - * Short-cut for poll(/"proc/kmsg") which simply checks - * for pending data, not the size; return the count of - * records, not the length. - */ - error = log_next_idx - syslog_idx; - } else { - u64 seq = syslog_seq; - u32 idx = syslog_idx; - enum log_flags prev = syslog_prev; - - error = 0; - while (seq < log_next_seq) { - struct log *msg = log_from_idx(idx); - - error += msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - error -= syslog_partial; - } - raw_spin_unlock_irq(&logbuf_lock); - break; - /* Size of the log buffer */ - case SYSLOG_ACTION_SIZE_BUFFER: - error = log_buf_len; - break; - default: - error = -EINVAL; - break; - } -out: - return error; -} - -SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) -{ - return do_syslog(type, buf, len, SYSLOG_FROM_READER); -} - -/* - * Call the console drivers, asking them to write out - * log_buf[start] to log_buf[end - 1]. - * The console_lock must be held. - */ -static void call_console_drivers(int level, const char *text, size_t len) -{ - struct console *con; - - trace_console(text, len); - - if (level >= console_loglevel && !ignore_loglevel) - return; - if (!console_drivers) - return; - - for_each_console(con) { - if (exclusive_console && con != exclusive_console) - continue; - if (!(con->flags & CON_ENABLED)) - continue; - if (!con->write) - continue; - if (!cpu_online(smp_processor_id()) && - !(con->flags & CON_ANYTIME)) - continue; - con->write(con, text, len); - } -} - -/* - * Zap console related locks when oopsing. Only zap at most once - * every 10 seconds, to leave time for slow consoles to print a - * full oops. - */ -static void zap_locks(void) -{ - static unsigned long oops_timestamp; - - if (time_after_eq(jiffies, oops_timestamp) && - !time_after(jiffies, oops_timestamp + 30 * HZ)) - return; - - oops_timestamp = jiffies; - - debug_locks_off(); - /* If a crash is occurring, make sure we can't deadlock */ - raw_spin_lock_init(&logbuf_lock); - /* And make sure that we print immediately */ - sema_init(&console_sem, 1); -} - -/* Check if we have any console registered that can be called early in boot. */ -static int have_callable_console(void) -{ - struct console *con; - - for_each_console(con) - if (con->flags & CON_ANYTIME) - return 1; - - return 0; -} - -/* - * Can we actually use the console at this time on this cpu? - * - * Console drivers may assume that per-cpu resources have - * been allocated. So unless they're explicitly marked as - * being able to cope (CON_ANYTIME) don't call them until - * this CPU is officially up. - */ -static inline int can_use_console(unsigned int cpu) -{ - return cpu_online(cpu) || have_callable_console(); -} - -/* - * Try to get console ownership to actually show the kernel - * messages from a 'printk'. Return true (and with the - * console_lock held, and 'console_locked' set) if it - * is successful, false otherwise. - * - * This gets called with the 'logbuf_lock' spinlock held and - * interrupts disabled. It should return with 'lockbuf_lock' - * released but interrupts still disabled. - */ -static int console_trylock_for_printk(unsigned int cpu) - __releases(&logbuf_lock) -{ - int retval = 0, wake = 0; - - if (console_trylock()) { - retval = 1; - - /* - * If we can't use the console, we need to release - * the console semaphore by hand to avoid flushing - * the buffer. We need to hold the console semaphore - * in order to do this test safely. - */ - if (!can_use_console(cpu)) { - console_locked = 0; - wake = 1; - retval = 0; - } - } - logbuf_cpu = UINT_MAX; - raw_spin_unlock(&logbuf_lock); - if (wake) - up(&console_sem); - return retval; -} - -int printk_delay_msec __read_mostly; - -static inline void printk_delay(void) -{ - if (unlikely(printk_delay_msec)) { - int m = printk_delay_msec; - - while (m--) { - mdelay(1); - touch_nmi_watchdog(); - } - } -} - -/* - * Continuation lines are buffered, and not committed to the record buffer - * until the line is complete, or a race forces it. The line fragments - * though, are printed immediately to the consoles to ensure everything has - * reached the console in case of a kernel crash. - */ -static struct cont { - char buf[LOG_LINE_MAX]; - size_t len; /* length == 0 means unused buffer */ - size_t cons; /* bytes written to console */ - struct task_struct *owner; /* task of first print*/ - u64 ts_nsec; /* time of first print */ - u8 level; /* log level of first message */ - u8 facility; /* log level of first message */ - enum log_flags flags; /* prefix, newline flags */ - bool flushed:1; /* buffer sealed and committed */ -} cont; - -static void cont_flush(enum log_flags flags) -{ - if (cont.flushed) - return; - if (cont.len == 0) - return; - - if (cont.cons) { - /* - * If a fragment of this line was directly flushed to the - * console; wait for the console to pick up the rest of the - * line. LOG_NOCONS suppresses a duplicated output. - */ - log_store(cont.facility, cont.level, flags | LOG_NOCONS, - cont.ts_nsec, NULL, 0, cont.buf, cont.len); - cont.flags = flags; - cont.flushed = true; - } else { - /* - * If no fragment of this line ever reached the console, - * just submit it to the store and free the buffer. - */ - log_store(cont.facility, cont.level, flags, 0, - NULL, 0, cont.buf, cont.len); - cont.len = 0; - } -} - -static bool cont_add(int facility, int level, const char *text, size_t len) -{ - if (cont.len && cont.flushed) - return false; - - if (cont.len + len > sizeof(cont.buf)) { - /* the line gets too long, split it up in separate records */ - cont_flush(LOG_CONT); - return false; - } - - if (!cont.len) { - cont.facility = facility; - cont.level = level; - cont.owner = current; - cont.ts_nsec = local_clock(); - cont.flags = 0; - cont.cons = 0; - cont.flushed = false; - } - - memcpy(cont.buf + cont.len, text, len); - cont.len += len; - - if (cont.len > (sizeof(cont.buf) * 80) / 100) - cont_flush(LOG_CONT); - - return true; -} - -static size_t cont_print_text(char *text, size_t size) -{ - size_t textlen = 0; - size_t len; - - if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) { - textlen += print_time(cont.ts_nsec, text); - size -= textlen; - } - - len = cont.len - cont.cons; - if (len > 0) { - if (len+1 > size) - len = size-1; - memcpy(text + textlen, cont.buf + cont.cons, len); - textlen += len; - cont.cons = cont.len; - } - - if (cont.flushed) { - if (cont.flags & LOG_NEWLINE) - text[textlen++] = '\n'; - /* got everything, release buffer */ - cont.len = 0; - } - return textlen; -} - -asmlinkage int vprintk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, va_list args) -{ - static int recursion_bug; - static char textbuf[LOG_LINE_MAX]; - char *text = textbuf; - size_t text_len; - enum log_flags lflags = 0; - unsigned long flags; - int this_cpu; - int printed_len = 0; - - boot_delay_msec(level); - printk_delay(); - - /* This stops the holder of console_sem just where we want him */ - local_irq_save(flags); - this_cpu = smp_processor_id(); - - /* - * Ouch, printk recursed into itself! - */ - if (unlikely(logbuf_cpu == this_cpu)) { - /* - * If a crash is occurring during printk() on this CPU, - * then try to get the crash message out but make sure - * we can't deadlock. Otherwise just return to avoid the - * recursion and return - but flag the recursion so that - * it can be printed at the next appropriate moment: - */ - if (!oops_in_progress && !lockdep_recursing(current)) { - recursion_bug = 1; - goto out_restore_irqs; - } - zap_locks(); - } - - lockdep_off(); - raw_spin_lock(&logbuf_lock); - logbuf_cpu = this_cpu; - - if (recursion_bug) { - static const char recursion_msg[] = - "BUG: recent printk recursion!"; - - recursion_bug = 0; - printed_len += strlen(recursion_msg); - /* emit KERN_CRIT message */ - log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, - NULL, 0, recursion_msg, printed_len); - } - - /* - * The printf needs to come first; we need the syslog - * prefix which might be passed-in as a parameter. - */ - text_len = vscnprintf(text, sizeof(textbuf), fmt, args); - - /* mark and strip a trailing newline */ - if (text_len && text[text_len-1] == '\n') { - text_len--; - lflags |= LOG_NEWLINE; - } - - /* strip kernel syslog prefix and extract log level or control flags */ - if (facility == 0) { - int kern_level = printk_get_level(text); - - if (kern_level) { - const char *end_of_header = printk_skip_level(text); - switch (kern_level) { - case '0' ... '7': - if (level == -1) - level = kern_level - '0'; - case 'd': /* KERN_DEFAULT */ - lflags |= LOG_PREFIX; - case 'c': /* KERN_CONT */ - break; - } - text_len -= end_of_header - text; - text = (char *)end_of_header; - } - } - - if (level == -1) - level = default_message_loglevel; - - if (dict) - lflags |= LOG_PREFIX|LOG_NEWLINE; - - if (!(lflags & LOG_NEWLINE)) { - /* - * Flush the conflicting buffer. An earlier newline was missing, - * or another task also prints continuation lines. - */ - if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) - cont_flush(LOG_NEWLINE); - - /* buffer line if possible, otherwise store it right away */ - if (!cont_add(facility, level, text, text_len)) - log_store(facility, level, lflags | LOG_CONT, 0, - dict, dictlen, text, text_len); - } else { - bool stored = false; - - /* - * If an earlier newline was missing and it was the same task, - * either merge it with the current buffer and flush, or if - * there was a race with interrupts (prefix == true) then just - * flush it out and store this line separately. - */ - if (cont.len && cont.owner == current) { - if (!(lflags & LOG_PREFIX)) - stored = cont_add(facility, level, text, text_len); - cont_flush(LOG_NEWLINE); - } - - if (!stored) - log_store(facility, level, lflags, 0, - dict, dictlen, text, text_len); - } - printed_len += text_len; - - /* - * Try to acquire and then immediately release the console semaphore. - * The release will print out buffers and wake up /dev/kmsg and syslog() - * users. - * - * The console_trylock_for_printk() function will release 'logbuf_lock' - * regardless of whether it actually gets the console semaphore or not. - */ - if (console_trylock_for_printk(this_cpu)) - console_unlock(); - - lockdep_on(); -out_restore_irqs: - local_irq_restore(flags); - - return printed_len; -} -EXPORT_SYMBOL(vprintk_emit); - -asmlinkage int vprintk(const char *fmt, va_list args) -{ - return vprintk_emit(0, -1, NULL, 0, fmt, args); -} -EXPORT_SYMBOL(vprintk); - -asmlinkage int printk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, ...) -{ - va_list args; - int r; - - va_start(args, fmt); - r = vprintk_emit(facility, level, dict, dictlen, fmt, args); - va_end(args); - - return r; -} -EXPORT_SYMBOL(printk_emit); - -/** - * printk - print a kernel message - * @fmt: format string - * - * This is printk(). It can be called from any context. We want it to work. - * - * We try to grab the console_lock. If we succeed, it's easy - we log the - * output and call the console drivers. If we fail to get the semaphore, we - * place the output into the log buffer and return. The current holder of - * the console_sem will notice the new output in console_unlock(); and will - * send it to the consoles before releasing the lock. - * - * One effect of this deferred printing is that code which calls printk() and - * then changes console_loglevel may break. This is because console_loglevel - * is inspected when the actual printing occurs. - * - * See also: - * printf(3) - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -asmlinkage int printk(const char *fmt, ...) -{ - va_list args; - int r; - -#ifdef CONFIG_KGDB_KDB - if (unlikely(kdb_trap_printk)) { - va_start(args, fmt); - r = vkdb_printf(fmt, args); - va_end(args); - return r; - } -#endif - va_start(args, fmt); - r = vprintk_emit(0, -1, NULL, 0, fmt, args); - va_end(args); - - return r; -} -EXPORT_SYMBOL(printk); - -#else /* CONFIG_PRINTK */ - -#define LOG_LINE_MAX 0 -#define PREFIX_MAX 0 -#define LOG_LINE_MAX 0 -static u64 syslog_seq; -static u32 syslog_idx; -static u64 console_seq; -static u32 console_idx; -static enum log_flags syslog_prev; -static u64 log_first_seq; -static u32 log_first_idx; -static u64 log_next_seq; -static enum log_flags console_prev; -static struct cont { - size_t len; - size_t cons; - u8 level; - bool flushed:1; -} cont; -static struct log *log_from_idx(u32 idx) { return NULL; } -static u32 log_next(u32 idx) { return 0; } -static void call_console_drivers(int level, const char *text, size_t len) {} -static size_t msg_print_text(const struct log *msg, enum log_flags prev, - bool syslog, char *buf, size_t size) { return 0; } -static size_t cont_print_text(char *text, size_t size) { return 0; } - -#endif /* CONFIG_PRINTK */ - -#ifdef CONFIG_EARLY_PRINTK -struct console *early_console; - -void early_vprintk(const char *fmt, va_list ap) -{ - if (early_console) { - char buf[512]; - int n = vscnprintf(buf, sizeof(buf), fmt, ap); - - early_console->write(early_console, buf, n); - } -} - -asmlinkage void early_printk(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - early_vprintk(fmt, ap); - va_end(ap); -} -#endif - -static int __add_preferred_console(char *name, int idx, char *options, - char *brl_options) -{ - struct console_cmdline *c; - int i; - - /* - * See if this tty is not yet registered, and - * if we have a slot free. - */ - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - if (!brl_options) - selected_console = i; - return 0; - } - if (i == MAX_CMDLINECONSOLES) - return -E2BIG; - if (!brl_options) - selected_console = i; - c = &console_cmdline[i]; - strlcpy(c->name, name, sizeof(c->name)); - c->options = options; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - c->brl_options = brl_options; -#endif - c->index = idx; - return 0; -} -/* - * Set up a list of consoles. Called from init/main.c - */ -static int __init console_setup(char *str) -{ - char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */ - char *s, *options, *brl_options = NULL; - int idx; - -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (!memcmp(str, "brl,", 4)) { - brl_options = ""; - str += 4; - } else if (!memcmp(str, "brl=", 4)) { - brl_options = str + 4; - str = strchr(brl_options, ','); - if (!str) { - printk(KERN_ERR "need port name after brl=\n"); - return 1; - } - *(str++) = 0; - } -#endif - - /* - * Decode str into name, index, options. - */ - if (str[0] >= '0' && str[0] <= '9') { - strcpy(buf, "ttyS"); - strncpy(buf + 4, str, sizeof(buf) - 5); - } else { - strncpy(buf, str, sizeof(buf) - 1); - } - buf[sizeof(buf) - 1] = 0; - if ((options = strchr(str, ',')) != NULL) - *(options++) = 0; -#ifdef __sparc__ - if (!strcmp(str, "ttya")) - strcpy(buf, "ttyS0"); - if (!strcmp(str, "ttyb")) - strcpy(buf, "ttyS1"); -#endif - for (s = buf; *s; s++) - if ((*s >= '0' && *s <= '9') || *s == ',') - break; - idx = simple_strtoul(s, NULL, 10); - *s = 0; - - __add_preferred_console(buf, idx, options, brl_options); - console_set_on_cmdline = 1; - return 1; -} -__setup("console=", console_setup); - -/** - * add_preferred_console - add a device to the list of preferred consoles. - * @name: device name - * @idx: device index - * @options: options for this console - * - * The last preferred console added will be used for kernel messages - * and stdin/out/err for init. Normally this is used by console_setup - * above to handle user-supplied console arguments; however it can also - * be used by arch-specific code either to override the user or more - * commonly to provide a default console (ie from PROM variables) when - * the user has not supplied one. - */ -int add_preferred_console(char *name, int idx, char *options) -{ - return __add_preferred_console(name, idx, options, NULL); -} - -int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options) -{ - struct console_cmdline *c; - int i; - - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - c = &console_cmdline[i]; - strlcpy(c->name, name_new, sizeof(c->name)); - c->name[sizeof(c->name) - 1] = 0; - c->options = options; - c->index = idx_new; - return i; - } - /* not found */ - return -1; -} - -bool console_suspend_enabled = 1; -EXPORT_SYMBOL(console_suspend_enabled); - -static int __init console_suspend_disable(char *str) -{ - console_suspend_enabled = 0; - return 1; -} -__setup("no_console_suspend", console_suspend_disable); -module_param_named(console_suspend, console_suspend_enabled, - bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(console_suspend, "suspend console during suspend" - " and hibernate operations"); - -/** - * suspend_console - suspend the console subsystem - * - * This disables printk() while we go into suspend states - */ -void suspend_console(void) -{ - if (!console_suspend_enabled) - return; - printk("Suspending console(s) (use no_console_suspend to debug)\n"); - console_lock(); - console_suspended = 1; - up(&console_sem); -} - -void resume_console(void) -{ - if (!console_suspend_enabled) - return; - down(&console_sem); - console_suspended = 0; - console_unlock(); -} - -/** - * console_cpu_notify - print deferred console messages after CPU hotplug - * @self: notifier struct - * @action: CPU hotplug event - * @hcpu: unused - * - * If printk() is called from a CPU that is not online yet, the messages - * will be spooled but will not show up on the console. This function is - * called when a new CPU comes online (or fails to come up), and ensures - * that any such output gets printed. - */ -static int console_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - switch (action) { - case CPU_ONLINE: - case CPU_DEAD: - case CPU_DOWN_FAILED: - case CPU_UP_CANCELED: - console_lock(); - console_unlock(); - } - return NOTIFY_OK; -} - -/** - * console_lock - lock the console system for exclusive use. - * - * Acquires a lock which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. - * - * Can sleep, returns nothing. - */ -void console_lock(void) -{ - might_sleep(); - - down(&console_sem); - if (console_suspended) - return; - console_locked = 1; - console_may_schedule = 1; - mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_); -} -EXPORT_SYMBOL(console_lock); - -/** - * console_trylock - try to lock the console system for exclusive use. - * - * Tried to acquire a lock which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. - * - * returns 1 on success, and 0 on failure to acquire the lock. - */ -int console_trylock(void) -{ - if (down_trylock(&console_sem)) - return 0; - if (console_suspended) { - up(&console_sem); - return 0; - } - console_locked = 1; - console_may_schedule = 0; - mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_); - return 1; -} -EXPORT_SYMBOL(console_trylock); - -int is_console_locked(void) -{ - return console_locked; -} - -static void console_cont_flush(char *text, size_t size) -{ - unsigned long flags; - size_t len; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - - if (!cont.len) - goto out; - - /* - * We still queue earlier records, likely because the console was - * busy. The earlier ones need to be printed before this one, we - * did not flush any fragment so far, so just let it queue up. - */ - if (console_seq < log_next_seq && !cont.cons) - goto out; - - len = cont_print_text(text, size); - raw_spin_unlock(&logbuf_lock); - stop_critical_timings(); - call_console_drivers(cont.level, text, len); - start_critical_timings(); - local_irq_restore(flags); - return; -out: - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -} - -/** - * console_unlock - unlock the console system - * - * Releases the console_lock which the caller holds on the console system - * and the console driver list. - * - * While the console_lock was held, console output may have been buffered - * by printk(). If this is the case, console_unlock(); emits - * the output prior to releasing the lock. - * - * If there is output waiting, we wake /dev/kmsg and syslog() users. - * - * console_unlock(); may be called from any context. - */ -void console_unlock(void) -{ - static char text[LOG_LINE_MAX + PREFIX_MAX]; - static u64 seen_seq; - unsigned long flags; - bool wake_klogd = false; - bool retry; - - if (console_suspended) { - up(&console_sem); - return; - } - - console_may_schedule = 0; - - /* flush buffered message fragment immediately to console */ - console_cont_flush(text, sizeof(text)); -again: - for (;;) { - struct log *msg; - size_t len; - int level; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - if (seen_seq != log_next_seq) { - wake_klogd = true; - seen_seq = log_next_seq; - } - - if (console_seq < log_first_seq) { - /* messages are gone, move to first one */ - console_seq = log_first_seq; - console_idx = log_first_idx; - console_prev = 0; - } -skip: - if (console_seq == log_next_seq) - break; - - msg = log_from_idx(console_idx); - if (msg->flags & LOG_NOCONS) { - /* - * Skip record we have buffered and already printed - * directly to the console when we received it. - */ - console_idx = log_next(console_idx); - console_seq++; - /* - * We will get here again when we register a new - * CON_PRINTBUFFER console. Clear the flag so we - * will properly dump everything later. - */ - msg->flags &= ~LOG_NOCONS; - console_prev = msg->flags; - goto skip; - } - - level = msg->level; - len = msg_print_text(msg, console_prev, false, - text, sizeof(text)); - console_idx = log_next(console_idx); - console_seq++; - console_prev = msg->flags; - raw_spin_unlock(&logbuf_lock); - - stop_critical_timings(); /* don't trace print latency */ - call_console_drivers(level, text, len); - start_critical_timings(); - local_irq_restore(flags); - } - console_locked = 0; - mutex_release(&console_lock_dep_map, 1, _RET_IP_); - - /* Release the exclusive_console once it is used */ - if (unlikely(exclusive_console)) - exclusive_console = NULL; - - raw_spin_unlock(&logbuf_lock); - - up(&console_sem); - - /* - * Someone could have filled up the buffer again, so re-check if there's - * something to flush. In case we cannot trylock the console_sem again, - * there's a new owner and the console_unlock() from them will do the - * flush, no worries. - */ - raw_spin_lock(&logbuf_lock); - retry = console_seq != log_next_seq; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - if (retry && console_trylock()) - goto again; - - if (wake_klogd) - wake_up_klogd(); -} -EXPORT_SYMBOL(console_unlock); - -/** - * console_conditional_schedule - yield the CPU if required - * - * If the console code is currently allowed to sleep, and - * if this CPU should yield the CPU to another task, do - * so here. - * - * Must be called within console_lock();. - */ -void __sched console_conditional_schedule(void) -{ - if (console_may_schedule) - cond_resched(); -} -EXPORT_SYMBOL(console_conditional_schedule); - -void console_unblank(void) -{ - struct console *c; - - /* - * console_unblank can no longer be called in interrupt context unless - * oops_in_progress is set to 1.. - */ - if (oops_in_progress) { - if (down_trylock(&console_sem) != 0) - return; - } else - console_lock(); - - console_locked = 1; - console_may_schedule = 0; - for_each_console(c) - if ((c->flags & CON_ENABLED) && c->unblank) - c->unblank(); - console_unlock(); -} - -/* - * Return the console tty driver structure and its associated index - */ -struct tty_driver *console_device(int *index) -{ - struct console *c; - struct tty_driver *driver = NULL; - - console_lock(); - for_each_console(c) { - if (!c->device) - continue; - driver = c->device(c, index); - if (driver) - break; - } - console_unlock(); - return driver; -} - -/* - * Prevent further output on the passed console device so that (for example) - * serial drivers can disable console output before suspending a port, and can - * re-enable output afterwards. - */ -void console_stop(struct console *console) -{ - console_lock(); - console->flags &= ~CON_ENABLED; - console_unlock(); -} -EXPORT_SYMBOL(console_stop); - -void console_start(struct console *console) -{ - console_lock(); - console->flags |= CON_ENABLED; - console_unlock(); -} -EXPORT_SYMBOL(console_start); - -static int __read_mostly keep_bootcon; - -static int __init keep_bootcon_setup(char *str) -{ - keep_bootcon = 1; - printk(KERN_INFO "debug: skip boot console de-registration.\n"); - - return 0; -} - -early_param("keep_bootcon", keep_bootcon_setup); - -/* - * The console driver calls this routine during kernel initialization - * to register the console printing procedure with printk() and to - * print any messages that were printed by the kernel before the - * console driver was initialized. - * - * This can happen pretty early during the boot process (because of - * early_printk) - sometimes before setup_arch() completes - be careful - * of what kernel features are used - they may not be initialised yet. - * - * There are two types of consoles - bootconsoles (early_printk) and - * "real" consoles (everything which is not a bootconsole) which are - * handled differently. - * - Any number of bootconsoles can be registered at any time. - * - As soon as a "real" console is registered, all bootconsoles - * will be unregistered automatically. - * - Once a "real" console is registered, any attempt to register a - * bootconsoles will be rejected - */ -void register_console(struct console *newcon) -{ - int i; - unsigned long flags; - struct console *bcon = NULL; - - /* - * before we register a new CON_BOOT console, make sure we don't - * already have a valid console - */ - if (console_drivers && newcon->flags & CON_BOOT) { - /* find the last or real console */ - for_each_console(bcon) { - if (!(bcon->flags & CON_BOOT)) { - printk(KERN_INFO "Too late to register bootconsole %s%d\n", - newcon->name, newcon->index); - return; - } - } - } - - if (console_drivers && console_drivers->flags & CON_BOOT) - bcon = console_drivers; - - if (preferred_console < 0 || bcon || !console_drivers) - preferred_console = selected_console; - - if (newcon->early_setup) - newcon->early_setup(); - - /* - * See if we want to use this console driver. If we - * didn't select a console we take the first one - * that registers here. - */ - if (preferred_console < 0) { - if (newcon->index < 0) - newcon->index = 0; - if (newcon->setup == NULL || - newcon->setup(newcon, NULL) == 0) { - newcon->flags |= CON_ENABLED; - if (newcon->device) { - newcon->flags |= CON_CONSDEV; - preferred_console = 0; - } - } - } - - /* - * See if this console matches one we selected on - * the command line. - */ - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; - i++) { - if (strcmp(console_cmdline[i].name, newcon->name) != 0) - continue; - if (newcon->index >= 0 && - newcon->index != console_cmdline[i].index) - continue; - if (newcon->index < 0) - newcon->index = console_cmdline[i].index; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (console_cmdline[i].brl_options) { - newcon->flags |= CON_BRL; - braille_register_console(newcon, - console_cmdline[i].index, - console_cmdline[i].options, - console_cmdline[i].brl_options); - return; - } -#endif - if (newcon->setup && - newcon->setup(newcon, console_cmdline[i].options) != 0) - break; - newcon->flags |= CON_ENABLED; - newcon->index = console_cmdline[i].index; - if (i == selected_console) { - newcon->flags |= CON_CONSDEV; - preferred_console = selected_console; - } - break; - } - - if (!(newcon->flags & CON_ENABLED)) - return; - - /* - * If we have a bootconsole, and are switching to a real console, - * don't print everything out again, since when the boot console, and - * the real console are the same physical device, it's annoying to - * see the beginning boot messages twice - */ - if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) - newcon->flags &= ~CON_PRINTBUFFER; - - /* - * Put this console in the list - keep the - * preferred driver at the head of the list. - */ - console_lock(); - if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { - newcon->next = console_drivers; - console_drivers = newcon; - if (newcon->next) - newcon->next->flags &= ~CON_CONSDEV; - } else { - newcon->next = console_drivers->next; - console_drivers->next = newcon; - } - if (newcon->flags & CON_PRINTBUFFER) { - /* - * console_unlock(); will print out the buffered messages - * for us. - */ - raw_spin_lock_irqsave(&logbuf_lock, flags); - console_seq = syslog_seq; - console_idx = syslog_idx; - console_prev = syslog_prev; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - /* - * We're about to replay the log buffer. Only do this to the - * just-registered console to avoid excessive message spam to - * the already-registered consoles. - */ - exclusive_console = newcon; - } - console_unlock(); - console_sysfs_notify(); - - /* - * By unregistering the bootconsoles after we enable the real console - * we get the "console xxx enabled" message on all the consoles - - * boot consoles, real consoles, etc - this is to ensure that end - * users know there might be something in the kernel's log buffer that - * went to the bootconsole (that they do not see on the real console) - */ - if (bcon && - ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && - !keep_bootcon) { - /* we need to iterate through twice, to make sure we print - * everything out, before we unregister the console(s) - */ - printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", - newcon->name, newcon->index); - for_each_console(bcon) - if (bcon->flags & CON_BOOT) - unregister_console(bcon); - } else { - printk(KERN_INFO "%sconsole [%s%d] enabled\n", - (newcon->flags & CON_BOOT) ? "boot" : "" , - newcon->name, newcon->index); - } -} -EXPORT_SYMBOL(register_console); - -int unregister_console(struct console *console) -{ - struct console *a, *b; - int res = 1; - -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (console->flags & CON_BRL) - return braille_unregister_console(console); -#endif - - console_lock(); - if (console_drivers == console) { - console_drivers=console->next; - res = 0; - } else if (console_drivers) { - for (a=console_drivers->next, b=console_drivers ; - a; b=a, a=b->next) { - if (a == console) { - b->next = a->next; - res = 0; - break; - } - } - } - - /* - * If this isn't the last console and it has CON_CONSDEV set, we - * need to set it on the next preferred console. - */ - if (console_drivers != NULL && console->flags & CON_CONSDEV) - console_drivers->flags |= CON_CONSDEV; - - console_unlock(); - console_sysfs_notify(); - return res; -} -EXPORT_SYMBOL(unregister_console); - -static int __init printk_late_init(void) -{ - struct console *con; - - for_each_console(con) { - if (!keep_bootcon && con->flags & CON_BOOT) { - printk(KERN_INFO "turn off boot console %s%d\n", - con->name, con->index); - unregister_console(con); - } - } - hotcpu_notifier(console_cpu_notify, 0); - return 0; -} -late_initcall(printk_late_init); - -#if defined CONFIG_PRINTK -/* - * Delayed printk version, for scheduler-internal messages: - */ -#define PRINTK_BUF_SIZE 512 - -#define PRINTK_PENDING_WAKEUP 0x01 -#define PRINTK_PENDING_SCHED 0x02 - -static DEFINE_PER_CPU(int, printk_pending); -static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); - -static void wake_up_klogd_work_func(struct irq_work *irq_work) -{ - int pending = __this_cpu_xchg(printk_pending, 0); - - if (pending & PRINTK_PENDING_SCHED) { - char *buf = __get_cpu_var(printk_sched_buf); - printk(KERN_WARNING "[sched_delayed] %s", buf); - } - - if (pending & PRINTK_PENDING_WAKEUP) - wake_up_interruptible(&log_wait); -} - -static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { - .func = wake_up_klogd_work_func, - .flags = IRQ_WORK_LAZY, -}; - -void wake_up_klogd(void) -{ - preempt_disable(); - if (waitqueue_active(&log_wait)) { - this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); - irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); - } - preempt_enable(); -} - -int printk_sched(const char *fmt, ...) -{ - unsigned long flags; - va_list args; - char *buf; - int r; - - local_irq_save(flags); - buf = __get_cpu_var(printk_sched_buf); - - va_start(args, fmt); - r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args); - va_end(args); - - __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); - irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); - local_irq_restore(flags); - - return r; -} - -/* - * printk rate limiting, lifted from the networking subsystem. - * - * This enforces a rate limit: not more than 10 kernel messages - * every 5s to make a denial-of-service attack impossible. - */ -DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); - -int __printk_ratelimit(const char *func) -{ - return ___ratelimit(&printk_ratelimit_state, func); -} -EXPORT_SYMBOL(__printk_ratelimit); - -/** - * printk_timed_ratelimit - caller-controlled printk ratelimiting - * @caller_jiffies: pointer to caller's state - * @interval_msecs: minimum interval between prints - * - * printk_timed_ratelimit() returns true if more than @interval_msecs - * milliseconds have elapsed since the last time printk_timed_ratelimit() - * returned true. - */ -bool printk_timed_ratelimit(unsigned long *caller_jiffies, - unsigned int interval_msecs) -{ - if (*caller_jiffies == 0 - || !time_in_range(jiffies, *caller_jiffies, - *caller_jiffies - + msecs_to_jiffies(interval_msecs))) { - *caller_jiffies = jiffies; - return true; - } - return false; -} -EXPORT_SYMBOL(printk_timed_ratelimit); - -static DEFINE_SPINLOCK(dump_list_lock); -static LIST_HEAD(dump_list); - -/** - * kmsg_dump_register - register a kernel log dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Adds a kernel log dumper to the system. The dump callback in the - * structure will be called when the kernel oopses or panics and must be - * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. - */ -int kmsg_dump_register(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EBUSY; - - /* The dump callback needs to be set */ - if (!dumper->dump) - return -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - /* Don't allow registering multiple times */ - if (!dumper->registered) { - dumper->registered = 1; - list_add_tail_rcu(&dumper->list, &dump_list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_register); - -/** - * kmsg_dump_unregister - unregister a kmsg dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Removes a dump device from the system. Returns zero on success and - * %-EINVAL otherwise. - */ -int kmsg_dump_unregister(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - if (dumper->registered) { - dumper->registered = 0; - list_del_rcu(&dumper->list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - synchronize_rcu(); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_unregister); - -static bool always_kmsg_dump; -module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); - -/** - * kmsg_dump - dump kernel log to kernel message dumpers. - * @reason: the reason (oops, panic etc) for dumping - * - * Call each of the registered dumper's dump() callback, which can - * retrieve the kmsg records with kmsg_dump_get_line() or - * kmsg_dump_get_buffer(). - */ -void kmsg_dump(enum kmsg_dump_reason reason) -{ - struct kmsg_dumper *dumper; - unsigned long flags; - - if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) - return; - - rcu_read_lock(); - list_for_each_entry_rcu(dumper, &dump_list, list) { - if (dumper->max_reason && reason > dumper->max_reason) - continue; - - /* initialize iterator with data about the stored records */ - dumper->active = true; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - dumper->cur_seq = clear_seq; - dumper->cur_idx = clear_idx; - dumper->next_seq = log_next_seq; - dumper->next_idx = log_next_idx; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - /* invoke dumper which will iterate over records */ - dumper->dump(dumper, reason); - - /* reset iterator */ - dumper->active = false; - } - rcu_read_unlock(); -} - -/** - * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - * - * The function is similar to kmsg_dump_get_line(), but grabs no locks. - */ -bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - struct log *msg; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - if (dumper->cur_seq < log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = log_first_seq; - dumper->cur_idx = log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= log_next_seq) - goto out; - - msg = log_from_idx(dumper->cur_idx); - l = msg_print_text(msg, 0, syslog, line, size); - - dumper->cur_idx = log_next(dumper->cur_idx); - dumper->cur_seq++; - ret = true; -out: - if (len) - *len = l; - return ret; -} - -/** - * kmsg_dump_get_line - retrieve one kmsg log line - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - unsigned long flags; - bool ret; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_line); - -/** - * kmsg_dump_get_buffer - copy kmsg log lines - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @buf: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the end of the kmsg buffer and fill the provided buffer - * with as many of the the *youngest* kmsg records that fit into it. - * If the buffer is large enough, all available kmsg records will be - * copied with a single call. - * - * Consecutive calls will fill the buffer with the next block of - * available older records, not including the earlier retrieved ones. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, - char *buf, size_t size, size_t *len) -{ - unsigned long flags; - u64 seq; - u32 idx; - u64 next_seq; - u32 next_idx; - enum log_flags prev; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - if (dumper->cur_seq < log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = log_first_seq; - dumper->cur_idx = log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= dumper->next_seq) { - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - goto out; - } - - /* calculate length of entire buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); - - l += msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - /* move first record forward until length fits into the buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (l > size && seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); - - l -= msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - /* last message in next interation */ - next_seq = seq; - next_idx = idx; - - l = 0; - prev = 0; - while (seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); - - l += msg_print_text(msg, prev, syslog, buf + l, size - l); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - dumper->next_seq = next_seq; - dumper->next_idx = next_idx; - ret = true; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -out: - if (len) - *len = l; - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); - -/** - * kmsg_dump_rewind_nolock - reset the interator (unlocked version) - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - * - * The function is similar to kmsg_dump_rewind(), but grabs no locks. - */ -void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) -{ - dumper->cur_seq = clear_seq; - dumper->cur_idx = clear_idx; - dumper->next_seq = log_next_seq; - dumper->next_idx = log_next_idx; -} - -/** - * kmsg_dump_rewind - reset the interator - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - */ -void kmsg_dump_rewind(struct kmsg_dumper *dumper) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - kmsg_dump_rewind_nolock(dumper); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -} -EXPORT_SYMBOL_GPL(kmsg_dump_rewind); - -static char dump_stack_arch_desc_str[128]; - -/** - * dump_stack_set_arch_desc - set arch-specific str to show with task dumps - * @fmt: printf-style format string - * @...: arguments for the format string - * - * The configured string will be printed right after utsname during task - * dumps. Usually used to add arch-specific system identifiers. If an - * arch wants to make use of such an ID string, it should initialize this - * as soon as possible during boot. - */ -void __init dump_stack_set_arch_desc(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str), - fmt, args); - va_end(args); -} - -/** - * dump_stack_print_info - print generic debug info for dump_stack() - * @log_lvl: log level - * - * Arch-specific dump_stack() implementations can use this function to - * print out the same debug information as the generic dump_stack(). - */ -void dump_stack_print_info(const char *log_lvl) -{ - printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n", - log_lvl, raw_smp_processor_id(), current->pid, current->comm, - print_tainted(), init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); - - if (dump_stack_arch_desc_str[0] != '\0') - printk("%sHardware name: %s\n", - log_lvl, dump_stack_arch_desc_str); - - print_worker_info(log_lvl, current); -} - -/** - * show_regs_print_info - print generic debug info for show_regs() - * @log_lvl: log level - * - * show_regs() implementations can use this function to print out generic - * debug information. - */ -void show_regs_print_info(const char *log_lvl) -{ - dump_stack_print_info(log_lvl); - - printk("%stask: %p ti: %p task.ti: %p\n", - log_lvl, current, current_thread_info(), - task_thread_info(current)); -} - -#endif diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile new file mode 100644 index 0000000..36d306d --- /dev/null +++ b/kernel/printk/Makefile @@ -0,0 +1 @@ +obj-y = printk.o diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c new file mode 100644 index 0000000..69b0890 --- /dev/null +++ b/kernel/printk/printk.c @@ -0,0 +1,2924 @@ +/* + * linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Modified to make sys_syslog() more flexible: added commands to + * return the last 4k of kernel messages, regardless of whether + * they've been read or not. Added option to suppress kernel printk's + * to the console. Added hook for sending the console messages + * elsewhere, in preparation for a serial line console (someday). + * Ted Ts'o, 2/11/93. + * Modified for sysctl support, 1/8/97, Chris Horn. + * Fixed SMP synchronization, 08/08/99, Manfred Spraul + * manfred@colorfullife.com + * Rewrote bits to get rid of console_lock + * 01Mar01 Andrew Morton + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For in_interrupt() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CREATE_TRACE_POINTS +#include + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL + +/* We show everything that is MORE important than this.. */ +#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ +#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ + +int console_printk[4] = { + DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ + DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ + MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ + DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ +}; + +/* + * Low level drivers may need that to know if they can schedule in + * their unblank() callback or not. So let's export it. + */ +int oops_in_progress; +EXPORT_SYMBOL(oops_in_progress); + +/* + * console_sem protects the console_drivers list, and also + * provides serialisation for access to the entire console + * driver system. + */ +static DEFINE_SEMAPHORE(console_sem); +struct console *console_drivers; +EXPORT_SYMBOL_GPL(console_drivers); + +#ifdef CONFIG_LOCKDEP +static struct lockdep_map console_lock_dep_map = { + .name = "console_lock" +}; +#endif + +/* + * This is used for debugging the mess that is the VT code by + * keeping track if we have the console semaphore held. It's + * definitely not the perfect debug tool (we don't know if _WE_ + * hold it are racing, but it helps tracking those weird code + * path in the console code where we end up in places I want + * locked without the console sempahore held + */ +static int console_locked, console_suspended; + +/* + * If exclusive_console is non-NULL then only this console is to be printed to. + */ +static struct console *exclusive_console; + +/* + * Array of consoles built from command line options (console=) + */ +struct console_cmdline +{ + char name[8]; /* Name of the driver */ + int index; /* Minor dev. to use */ + char *options; /* Options for the driver */ +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + char *brl_options; /* Options for braille driver */ +#endif +}; + +#define MAX_CMDLINECONSOLES 8 + +static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; +static int selected_console = -1; +static int preferred_console = -1; +int console_set_on_cmdline; +EXPORT_SYMBOL(console_set_on_cmdline); + +/* Flag: console code may call schedule() */ +static int console_may_schedule; + +/* + * The printk log buffer consists of a chain of concatenated variable + * length records. Every record starts with a record header, containing + * the overall length of the record. + * + * The heads to the first and last entry in the buffer, as well as the + * sequence numbers of these both entries are maintained when messages + * are stored.. + * + * If the heads indicate available messages, the length in the header + * tells the start next message. A length == 0 for the next message + * indicates a wrap-around to the beginning of the buffer. + * + * Every record carries the monotonic timestamp in microseconds, as well as + * the standard userspace syslog level and syslog facility. The usual + * kernel messages use LOG_KERN; userspace-injected messages always carry + * a matching syslog facility, by default LOG_USER. The origin of every + * message can be reliably determined that way. + * + * The human readable log message directly follows the message header. The + * length of the message text is stored in the header, the stored message + * is not terminated. + * + * Optionally, a message can carry a dictionary of properties (key/value pairs), + * to provide userspace with a machine-readable message context. + * + * Examples for well-defined, commonly used property names are: + * DEVICE=b12:8 device identifier + * b12:8 block dev_t + * c127:3 char dev_t + * n8 netdev ifindex + * +sound:card0 subsystem:devname + * SUBSYSTEM=pci driver-core subsystem name + * + * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value + * follows directly after a '=' character. Every property is terminated by + * a '\0' character. The last property is not terminated. + * + * Example of a message structure: + * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec + * 0008 34 00 record is 52 bytes long + * 000a 0b 00 text is 11 bytes long + * 000c 1f 00 dictionary is 23 bytes long + * 000e 03 00 LOG_KERN (facility) LOG_ERR (level) + * 0010 69 74 27 73 20 61 20 6c "it's a l" + * 69 6e 65 "ine" + * 001b 44 45 56 49 43 "DEVIC" + * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D" + * 52 49 56 45 52 3d 62 75 "RIVER=bu" + * 67 "g" + * 0032 00 00 00 padding to next message header + * + * The 'struct log' buffer header must never be directly exported to + * userspace, it is a kernel-private implementation detail that might + * need to be changed in the future, when the requirements change. + * + * /dev/kmsg exports the structured data in the following line format: + * "level,sequnum,timestamp;\n" + * + * The optional key/value pairs are attached as continuation lines starting + * with a space character and terminated by a newline. All possible + * non-prinatable characters are escaped in the "\xff" notation. + * + * Users of the export format should ignore possible additional values + * separated by ',', and find the message after the ';' character. + */ + +enum log_flags { + LOG_NOCONS = 1, /* already flushed, do not print to console */ + LOG_NEWLINE = 2, /* text ended with a newline */ + LOG_PREFIX = 4, /* text started with a prefix */ + LOG_CONT = 8, /* text is a fragment of a continuation line */ +}; + +struct log { + u64 ts_nsec; /* timestamp in nanoseconds */ + u16 len; /* length of entire record */ + u16 text_len; /* length of text buffer */ + u16 dict_len; /* length of dictionary buffer */ + u8 facility; /* syslog facility */ + u8 flags:5; /* internal record flags */ + u8 level:3; /* syslog level */ +}; + +/* + * The logbuf_lock protects kmsg buffer, indices, counters. It is also + * used in interesting ways to provide interlocking in console_unlock(); + */ +static DEFINE_RAW_SPINLOCK(logbuf_lock); + +#ifdef CONFIG_PRINTK +DECLARE_WAIT_QUEUE_HEAD(log_wait); +/* the next printk record to read by syslog(READ) or /proc/kmsg */ +static u64 syslog_seq; +static u32 syslog_idx; +static enum log_flags syslog_prev; +static size_t syslog_partial; + +/* index and sequence number of the first record stored in the buffer */ +static u64 log_first_seq; +static u32 log_first_idx; + +/* index and sequence number of the next record to store in the buffer */ +static u64 log_next_seq; +static u32 log_next_idx; + +/* the next printk record to write to the console */ +static u64 console_seq; +static u32 console_idx; +static enum log_flags console_prev; + +/* the next printk record to read after the last 'clear' command */ +static u64 clear_seq; +static u32 clear_idx; + +#define PREFIX_MAX 32 +#define LOG_LINE_MAX 1024 - PREFIX_MAX + +/* record buffer */ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) +#define LOG_ALIGN 4 +#else +#define LOG_ALIGN __alignof__(struct log) +#endif +#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) +static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); +static char *log_buf = __log_buf; +static u32 log_buf_len = __LOG_BUF_LEN; + +/* cpu currently holding logbuf_lock */ +static volatile unsigned int logbuf_cpu = UINT_MAX; + +/* human readable text of the record */ +static char *log_text(const struct log *msg) +{ + return (char *)msg + sizeof(struct log); +} + +/* optional key/value pair dictionary attached to the record */ +static char *log_dict(const struct log *msg) +{ + return (char *)msg + sizeof(struct log) + msg->text_len; +} + +/* get record by index; idx must point to valid msg */ +static struct log *log_from_idx(u32 idx) +{ + struct log *msg = (struct log *)(log_buf + idx); + + /* + * A length == 0 record is the end of buffer marker. Wrap around and + * read the message at the start of the buffer. + */ + if (!msg->len) + return (struct log *)log_buf; + return msg; +} + +/* get next record; idx must point to valid msg */ +static u32 log_next(u32 idx) +{ + struct log *msg = (struct log *)(log_buf + idx); + + /* length == 0 indicates the end of the buffer; wrap */ + /* + * A length == 0 record is the end of buffer marker. Wrap around and + * read the message at the start of the buffer as *this* one, and + * return the one after that. + */ + if (!msg->len) { + msg = (struct log *)log_buf; + return msg->len; + } + return idx + msg->len; +} + +/* insert record into the buffer, discard old ones, update heads */ +static void log_store(int facility, int level, + enum log_flags flags, u64 ts_nsec, + const char *dict, u16 dict_len, + const char *text, u16 text_len) +{ + struct log *msg; + u32 size, pad_len; + + /* number of '\0' padding bytes to next message */ + size = sizeof(struct log) + text_len + dict_len; + pad_len = (-size) & (LOG_ALIGN - 1); + size += pad_len; + + while (log_first_seq < log_next_seq) { + u32 free; + + if (log_next_idx > log_first_idx) + free = max(log_buf_len - log_next_idx, log_first_idx); + else + free = log_first_idx - log_next_idx; + + if (free > size + sizeof(struct log)) + break; + + /* drop old messages until we have enough contiuous space */ + log_first_idx = log_next(log_first_idx); + log_first_seq++; + } + + if (log_next_idx + size + sizeof(struct log) >= log_buf_len) { + /* + * This message + an additional empty header does not fit + * at the end of the buffer. Add an empty header with len == 0 + * to signify a wrap around. + */ + memset(log_buf + log_next_idx, 0, sizeof(struct log)); + log_next_idx = 0; + } + + /* fill message */ + msg = (struct log *)(log_buf + log_next_idx); + memcpy(log_text(msg), text, text_len); + msg->text_len = text_len; + memcpy(log_dict(msg), dict, dict_len); + msg->dict_len = dict_len; + msg->facility = facility; + msg->level = level & 7; + msg->flags = flags & 0x1f; + if (ts_nsec > 0) + msg->ts_nsec = ts_nsec; + else + msg->ts_nsec = local_clock(); + memset(log_dict(msg) + dict_len, 0, pad_len); + msg->len = sizeof(struct log) + text_len + dict_len + pad_len; + + /* insert message */ + log_next_idx += msg->len; + log_next_seq++; +} + +#ifdef CONFIG_SECURITY_DMESG_RESTRICT +int dmesg_restrict = 1; +#else +int dmesg_restrict; +#endif + +static int syslog_action_restricted(int type) +{ + if (dmesg_restrict) + return 1; + /* + * Unless restricted, we allow "read all" and "get buffer size" + * for everybody. + */ + return type != SYSLOG_ACTION_READ_ALL && + type != SYSLOG_ACTION_SIZE_BUFFER; +} + +static int check_syslog_permissions(int type, bool from_file) +{ + /* + * If this is from /proc/kmsg and we've already opened it, then we've + * already done the capabilities checks at open time. + */ + if (from_file && type != SYSLOG_ACTION_OPEN) + return 0; + + if (syslog_action_restricted(type)) { + if (capable(CAP_SYSLOG)) + return 0; + /* + * For historical reasons, accept CAP_SYS_ADMIN too, with + * a warning. + */ + if (capable(CAP_SYS_ADMIN)) { + pr_warn_once("%s (%d): Attempt to access syslog with " + "CAP_SYS_ADMIN but no CAP_SYSLOG " + "(deprecated).\n", + current->comm, task_pid_nr(current)); + return 0; + } + return -EPERM; + } + return security_syslog(type); +} + + +/* /dev/kmsg - userspace message inject/listen interface */ +struct devkmsg_user { + u64 seq; + u32 idx; + enum log_flags prev; + struct mutex lock; + char buf[8192]; +}; + +static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv, + unsigned long count, loff_t pos) +{ + char *buf, *line; + int i; + int level = default_message_loglevel; + int facility = 1; /* LOG_USER */ + size_t len = iov_length(iv, count); + ssize_t ret = len; + + if (len > LOG_LINE_MAX) + return -EINVAL; + buf = kmalloc(len+1, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + line = buf; + for (i = 0; i < count; i++) { + if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) { + ret = -EFAULT; + goto out; + } + line += iv[i].iov_len; + } + + /* + * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace + * the decimal value represents 32bit, the lower 3 bit are the log + * level, the rest are the log facility. + * + * If no prefix or no userspace facility is specified, we + * enforce LOG_USER, to be able to reliably distinguish + * kernel-generated messages from userspace-injected ones. + */ + line = buf; + if (line[0] == '<') { + char *endp = NULL; + + i = simple_strtoul(line+1, &endp, 10); + if (endp && endp[0] == '>') { + level = i & 7; + if (i >> 3) + facility = i >> 3; + endp++; + len -= endp - line; + line = endp; + } + } + line[len] = '\0'; + + printk_emit(facility, level, NULL, 0, "%s", line); +out: + kfree(buf); + return ret; +} + +static ssize_t devkmsg_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct devkmsg_user *user = file->private_data; + struct log *msg; + u64 ts_usec; + size_t i; + char cont = '-'; + size_t len; + ssize_t ret; + + if (!user) + return -EBADF; + + ret = mutex_lock_interruptible(&user->lock); + if (ret) + return ret; + raw_spin_lock_irq(&logbuf_lock); + while (user->seq == log_next_seq) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + raw_spin_unlock_irq(&logbuf_lock); + goto out; + } + + raw_spin_unlock_irq(&logbuf_lock); + ret = wait_event_interruptible(log_wait, + user->seq != log_next_seq); + if (ret) + goto out; + raw_spin_lock_irq(&logbuf_lock); + } + + if (user->seq < log_first_seq) { + /* our last seen message is gone, return error and reset */ + user->idx = log_first_idx; + user->seq = log_first_seq; + ret = -EPIPE; + raw_spin_unlock_irq(&logbuf_lock); + goto out; + } + + msg = log_from_idx(user->idx); + ts_usec = msg->ts_nsec; + do_div(ts_usec, 1000); + + /* + * If we couldn't merge continuation line fragments during the print, + * export the stored flags to allow an optional external merge of the + * records. Merging the records isn't always neccessarily correct, like + * when we hit a race during printing. In most cases though, it produces + * better readable output. 'c' in the record flags mark the first + * fragment of a line, '+' the following. + */ + if (msg->flags & LOG_CONT && !(user->prev & LOG_CONT)) + cont = 'c'; + else if ((msg->flags & LOG_CONT) || + ((user->prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))) + cont = '+'; + + len = sprintf(user->buf, "%u,%llu,%llu,%c;", + (msg->facility << 3) | msg->level, + user->seq, ts_usec, cont); + user->prev = msg->flags; + + /* escape non-printable characters */ + for (i = 0; i < msg->text_len; i++) { + unsigned char c = log_text(msg)[i]; + + if (c < ' ' || c >= 127 || c == '\\') + len += sprintf(user->buf + len, "\\x%02x", c); + else + user->buf[len++] = c; + } + user->buf[len++] = '\n'; + + if (msg->dict_len) { + bool line = true; + + for (i = 0; i < msg->dict_len; i++) { + unsigned char c = log_dict(msg)[i]; + + if (line) { + user->buf[len++] = ' '; + line = false; + } + + if (c == '\0') { + user->buf[len++] = '\n'; + line = true; + continue; + } + + if (c < ' ' || c >= 127 || c == '\\') { + len += sprintf(user->buf + len, "\\x%02x", c); + continue; + } + + user->buf[len++] = c; + } + user->buf[len++] = '\n'; + } + + user->idx = log_next(user->idx); + user->seq++; + raw_spin_unlock_irq(&logbuf_lock); + + if (len > count) { + ret = -EINVAL; + goto out; + } + + if (copy_to_user(buf, user->buf, len)) { + ret = -EFAULT; + goto out; + } + ret = len; +out: + mutex_unlock(&user->lock); + return ret; +} + +static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) +{ + struct devkmsg_user *user = file->private_data; + loff_t ret = 0; + + if (!user) + return -EBADF; + if (offset) + return -ESPIPE; + + raw_spin_lock_irq(&logbuf_lock); + switch (whence) { + case SEEK_SET: + /* the first record */ + user->idx = log_first_idx; + user->seq = log_first_seq; + break; + case SEEK_DATA: + /* + * The first record after the last SYSLOG_ACTION_CLEAR, + * like issued by 'dmesg -c'. Reading /dev/kmsg itself + * changes no global state, and does not clear anything. + */ + user->idx = clear_idx; + user->seq = clear_seq; + break; + case SEEK_END: + /* after the last record */ + user->idx = log_next_idx; + user->seq = log_next_seq; + break; + default: + ret = -EINVAL; + } + raw_spin_unlock_irq(&logbuf_lock); + return ret; +} + +static unsigned int devkmsg_poll(struct file *file, poll_table *wait) +{ + struct devkmsg_user *user = file->private_data; + int ret = 0; + + if (!user) + return POLLERR|POLLNVAL; + + poll_wait(file, &log_wait, wait); + + raw_spin_lock_irq(&logbuf_lock); + if (user->seq < log_next_seq) { + /* return error when data has vanished underneath us */ + if (user->seq < log_first_seq) + ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; + else + ret = POLLIN|POLLRDNORM; + } + raw_spin_unlock_irq(&logbuf_lock); + + return ret; +} + +static int devkmsg_open(struct inode *inode, struct file *file) +{ + struct devkmsg_user *user; + int err; + + /* write-only does not need any file context */ + if ((file->f_flags & O_ACCMODE) == O_WRONLY) + return 0; + + err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL, + SYSLOG_FROM_READER); + if (err) + return err; + + user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL); + if (!user) + return -ENOMEM; + + mutex_init(&user->lock); + + raw_spin_lock_irq(&logbuf_lock); + user->idx = log_first_idx; + user->seq = log_first_seq; + raw_spin_unlock_irq(&logbuf_lock); + + file->private_data = user; + return 0; +} + +static int devkmsg_release(struct inode *inode, struct file *file) +{ + struct devkmsg_user *user = file->private_data; + + if (!user) + return 0; + + mutex_destroy(&user->lock); + kfree(user); + return 0; +} + +const struct file_operations kmsg_fops = { + .open = devkmsg_open, + .read = devkmsg_read, + .aio_write = devkmsg_writev, + .llseek = devkmsg_llseek, + .poll = devkmsg_poll, + .release = devkmsg_release, +}; + +#ifdef CONFIG_KEXEC +/* + * This appends the listed symbols to /proc/vmcoreinfo + * + * /proc/vmcoreinfo is used by various utiilties, like crash and makedumpfile to + * obtain access to symbols that are otherwise very difficult to locate. These + * symbols are specifically used so that utilities can access and extract the + * dmesg log from a vmcore file after a crash. + */ +void log_buf_kexec_setup(void) +{ + VMCOREINFO_SYMBOL(log_buf); + VMCOREINFO_SYMBOL(log_buf_len); + VMCOREINFO_SYMBOL(log_first_idx); + VMCOREINFO_SYMBOL(log_next_idx); + /* + * Export struct log size and field offsets. User space tools can + * parse it and detect any changes to structure down the line. + */ + VMCOREINFO_STRUCT_SIZE(log); + VMCOREINFO_OFFSET(log, ts_nsec); + VMCOREINFO_OFFSET(log, len); + VMCOREINFO_OFFSET(log, text_len); + VMCOREINFO_OFFSET(log, dict_len); +} +#endif + +/* requested log_buf_len from kernel cmdline */ +static unsigned long __initdata new_log_buf_len; + +/* save requested log_buf_len since it's too early to process it */ +static int __init log_buf_len_setup(char *str) +{ + unsigned size = memparse(str, &str); + + if (size) + size = roundup_pow_of_two(size); + if (size > log_buf_len) + new_log_buf_len = size; + + return 0; +} +early_param("log_buf_len", log_buf_len_setup); + +void __init setup_log_buf(int early) +{ + unsigned long flags; + char *new_log_buf; + int free; + + if (!new_log_buf_len) + return; + + if (early) { + unsigned long mem; + + mem = memblock_alloc(new_log_buf_len, PAGE_SIZE); + if (!mem) + return; + new_log_buf = __va(mem); + } else { + new_log_buf = alloc_bootmem_nopanic(new_log_buf_len); + } + + if (unlikely(!new_log_buf)) { + pr_err("log_buf_len: %ld bytes not available\n", + new_log_buf_len); + return; + } + + raw_spin_lock_irqsave(&logbuf_lock, flags); + log_buf_len = new_log_buf_len; + log_buf = new_log_buf; + new_log_buf_len = 0; + free = __LOG_BUF_LEN - log_next_idx; + memcpy(log_buf, __log_buf, __LOG_BUF_LEN); + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + + pr_info("log_buf_len: %d\n", log_buf_len); + pr_info("early log buf free: %d(%d%%)\n", + free, (free * 100) / __LOG_BUF_LEN); +} + +static bool __read_mostly ignore_loglevel; + +static int __init ignore_loglevel_setup(char *str) +{ + ignore_loglevel = 1; + printk(KERN_INFO "debug: ignoring loglevel setting.\n"); + + return 0; +} + +early_param("ignore_loglevel", ignore_loglevel_setup); +module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to" + "print all kernel messages to the console."); + +#ifdef CONFIG_BOOT_PRINTK_DELAY + +static int boot_delay; /* msecs delay after each printk during bootup */ +static unsigned long long loops_per_msec; /* based on boot_delay */ + +static int __init boot_delay_setup(char *str) +{ + unsigned long lpj; + + lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ + loops_per_msec = (unsigned long long)lpj / 1000 * HZ; + + get_option(&str, &boot_delay); + if (boot_delay > 10 * 1000) + boot_delay = 0; + + pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, " + "HZ: %d, loops_per_msec: %llu\n", + boot_delay, preset_lpj, lpj, HZ, loops_per_msec); + return 1; +} +__setup("boot_delay=", boot_delay_setup); + +static void boot_delay_msec(int level) +{ + unsigned long long k; + unsigned long timeout; + + if ((boot_delay == 0 || system_state != SYSTEM_BOOTING) + || (level >= console_loglevel && !ignore_loglevel)) { + return; + } + + k = (unsigned long long)loops_per_msec * boot_delay; + + timeout = jiffies + msecs_to_jiffies(boot_delay); + while (k) { + k--; + cpu_relax(); + /* + * use (volatile) jiffies to prevent + * compiler reduction; loop termination via jiffies + * is secondary and may or may not happen. + */ + if (time_after(jiffies, timeout)) + break; + touch_nmi_watchdog(); + } +} +#else +static inline void boot_delay_msec(int level) +{ +} +#endif + +#if defined(CONFIG_PRINTK_TIME) +static bool printk_time = 1; +#else +static bool printk_time; +#endif +module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); + +static size_t print_time(u64 ts, char *buf) +{ + unsigned long rem_nsec; + + if (!printk_time) + return 0; + + rem_nsec = do_div(ts, 1000000000); + + if (!buf) + return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); + + return sprintf(buf, "[%5lu.%06lu] ", + (unsigned long)ts, rem_nsec / 1000); +} + +static size_t print_prefix(const struct log *msg, bool syslog, char *buf) +{ + size_t len = 0; + unsigned int prefix = (msg->facility << 3) | msg->level; + + if (syslog) { + if (buf) { + len += sprintf(buf, "<%u>", prefix); + } else { + len += 3; + if (prefix > 999) + len += 3; + else if (prefix > 99) + len += 2; + else if (prefix > 9) + len++; + } + } + + len += print_time(msg->ts_nsec, buf ? buf + len : NULL); + return len; +} + +static size_t msg_print_text(const struct log *msg, enum log_flags prev, + bool syslog, char *buf, size_t size) +{ + const char *text = log_text(msg); + size_t text_size = msg->text_len; + bool prefix = true; + bool newline = true; + size_t len = 0; + + if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) + prefix = false; + + if (msg->flags & LOG_CONT) { + if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) + prefix = false; + + if (!(msg->flags & LOG_NEWLINE)) + newline = false; + } + + do { + const char *next = memchr(text, '\n', text_size); + size_t text_len; + + if (next) { + text_len = next - text; + next++; + text_size -= next - text; + } else { + text_len = text_size; + } + + if (buf) { + if (print_prefix(msg, syslog, NULL) + + text_len + 1 >= size - len) + break; + + if (prefix) + len += print_prefix(msg, syslog, buf + len); + memcpy(buf + len, text, text_len); + len += text_len; + if (next || newline) + buf[len++] = '\n'; + } else { + /* SYSLOG_ACTION_* buffer size only calculation */ + if (prefix) + len += print_prefix(msg, syslog, NULL); + len += text_len; + if (next || newline) + len++; + } + + prefix = true; + text = next; + } while (text); + + return len; +} + +static int syslog_print(char __user *buf, int size) +{ + char *text; + struct log *msg; + int len = 0; + + text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); + if (!text) + return -ENOMEM; + + while (size > 0) { + size_t n; + size_t skip; + + raw_spin_lock_irq(&logbuf_lock); + if (syslog_seq < log_first_seq) { + /* messages are gone, move to first one */ + syslog_seq = log_first_seq; + syslog_idx = log_first_idx; + syslog_prev = 0; + syslog_partial = 0; + } + if (syslog_seq == log_next_seq) { + raw_spin_unlock_irq(&logbuf_lock); + break; + } + + skip = syslog_partial; + msg = log_from_idx(syslog_idx); + n = msg_print_text(msg, syslog_prev, true, text, + LOG_LINE_MAX + PREFIX_MAX); + if (n - syslog_partial <= size) { + /* message fits into buffer, move forward */ + syslog_idx = log_next(syslog_idx); + syslog_seq++; + syslog_prev = msg->flags; + n -= syslog_partial; + syslog_partial = 0; + } else if (!len){ + /* partial read(), remember position */ + n = size; + syslog_partial += n; + } else + n = 0; + raw_spin_unlock_irq(&logbuf_lock); + + if (!n) + break; + + if (copy_to_user(buf, text + skip, n)) { + if (!len) + len = -EFAULT; + break; + } + + len += n; + size -= n; + buf += n; + } + + kfree(text); + return len; +} + +static int syslog_print_all(char __user *buf, int size, bool clear) +{ + char *text; + int len = 0; + + text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); + if (!text) + return -ENOMEM; + + raw_spin_lock_irq(&logbuf_lock); + if (buf) { + u64 next_seq; + u64 seq; + u32 idx; + enum log_flags prev; + + if (clear_seq < log_first_seq) { + /* messages are gone, move to first available one */ + clear_seq = log_first_seq; + clear_idx = log_first_idx; + } + + /* + * Find first record that fits, including all following records, + * into the user-provided buffer for this dump. + */ + seq = clear_seq; + idx = clear_idx; + prev = 0; + while (seq < log_next_seq) { + struct log *msg = log_from_idx(idx); + + len += msg_print_text(msg, prev, true, NULL, 0); + prev = msg->flags; + idx = log_next(idx); + seq++; + } + + /* move first record forward until length fits into the buffer */ + seq = clear_seq; + idx = clear_idx; + prev = 0; + while (len > size && seq < log_next_seq) { + struct log *msg = log_from_idx(idx); + + len -= msg_print_text(msg, prev, true, NULL, 0); + prev = msg->flags; + idx = log_next(idx); + seq++; + } + + /* last message fitting into this dump */ + next_seq = log_next_seq; + + len = 0; + prev = 0; + while (len >= 0 && seq < next_seq) { + struct log *msg = log_from_idx(idx); + int textlen; + + textlen = msg_print_text(msg, prev, true, text, + LOG_LINE_MAX + PREFIX_MAX); + if (textlen < 0) { + len = textlen; + break; + } + idx = log_next(idx); + seq++; + prev = msg->flags; + + raw_spin_unlock_irq(&logbuf_lock); + if (copy_to_user(buf + len, text, textlen)) + len = -EFAULT; + else + len += textlen; + raw_spin_lock_irq(&logbuf_lock); + + if (seq < log_first_seq) { + /* messages are gone, move to next one */ + seq = log_first_seq; + idx = log_first_idx; + prev = 0; + } + } + } + + if (clear) { + clear_seq = log_next_seq; + clear_idx = log_next_idx; + } + raw_spin_unlock_irq(&logbuf_lock); + + kfree(text); + return len; +} + +int do_syslog(int type, char __user *buf, int len, bool from_file) +{ + bool clear = false; + static int saved_console_loglevel = -1; + int error; + + error = check_syslog_permissions(type, from_file); + if (error) + goto out; + + error = security_syslog(type); + if (error) + return error; + + switch (type) { + case SYSLOG_ACTION_CLOSE: /* Close log */ + break; + case SYSLOG_ACTION_OPEN: /* Open log */ + break; + case SYSLOG_ACTION_READ: /* Read from log */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + if (!access_ok(VERIFY_WRITE, buf, len)) { + error = -EFAULT; + goto out; + } + error = wait_event_interruptible(log_wait, + syslog_seq != log_next_seq); + if (error) + goto out; + error = syslog_print(buf, len); + break; + /* Read/clear last kernel messages */ + case SYSLOG_ACTION_READ_CLEAR: + clear = true; + /* FALL THRU */ + /* Read last kernel messages */ + case SYSLOG_ACTION_READ_ALL: + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + if (!access_ok(VERIFY_WRITE, buf, len)) { + error = -EFAULT; + goto out; + } + error = syslog_print_all(buf, len, clear); + break; + /* Clear ring buffer */ + case SYSLOG_ACTION_CLEAR: + syslog_print_all(NULL, 0, true); + break; + /* Disable logging to console */ + case SYSLOG_ACTION_CONSOLE_OFF: + if (saved_console_loglevel == -1) + saved_console_loglevel = console_loglevel; + console_loglevel = minimum_console_loglevel; + break; + /* Enable logging to console */ + case SYSLOG_ACTION_CONSOLE_ON: + if (saved_console_loglevel != -1) { + console_loglevel = saved_console_loglevel; + saved_console_loglevel = -1; + } + break; + /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_LEVEL: + error = -EINVAL; + if (len < 1 || len > 8) + goto out; + if (len < minimum_console_loglevel) + len = minimum_console_loglevel; + console_loglevel = len; + /* Implicitly re-enable logging to console */ + saved_console_loglevel = -1; + error = 0; + break; + /* Number of chars in the log buffer */ + case SYSLOG_ACTION_SIZE_UNREAD: + raw_spin_lock_irq(&logbuf_lock); + if (syslog_seq < log_first_seq) { + /* messages are gone, move to first one */ + syslog_seq = log_first_seq; + syslog_idx = log_first_idx; + syslog_prev = 0; + syslog_partial = 0; + } + if (from_file) { + /* + * Short-cut for poll(/"proc/kmsg") which simply checks + * for pending data, not the size; return the count of + * records, not the length. + */ + error = log_next_idx - syslog_idx; + } else { + u64 seq = syslog_seq; + u32 idx = syslog_idx; + enum log_flags prev = syslog_prev; + + error = 0; + while (seq < log_next_seq) { + struct log *msg = log_from_idx(idx); + + error += msg_print_text(msg, prev, true, NULL, 0); + idx = log_next(idx); + seq++; + prev = msg->flags; + } + error -= syslog_partial; + } + raw_spin_unlock_irq(&logbuf_lock); + break; + /* Size of the log buffer */ + case SYSLOG_ACTION_SIZE_BUFFER: + error = log_buf_len; + break; + default: + error = -EINVAL; + break; + } +out: + return error; +} + +SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) +{ + return do_syslog(type, buf, len, SYSLOG_FROM_READER); +} + +/* + * Call the console drivers, asking them to write out + * log_buf[start] to log_buf[end - 1]. + * The console_lock must be held. + */ +static void call_console_drivers(int level, const char *text, size_t len) +{ + struct console *con; + + trace_console(text, len); + + if (level >= console_loglevel && !ignore_loglevel) + return; + if (!console_drivers) + return; + + for_each_console(con) { + if (exclusive_console && con != exclusive_console) + continue; + if (!(con->flags & CON_ENABLED)) + continue; + if (!con->write) + continue; + if (!cpu_online(smp_processor_id()) && + !(con->flags & CON_ANYTIME)) + continue; + con->write(con, text, len); + } +} + +/* + * Zap console related locks when oopsing. Only zap at most once + * every 10 seconds, to leave time for slow consoles to print a + * full oops. + */ +static void zap_locks(void) +{ + static unsigned long oops_timestamp; + + if (time_after_eq(jiffies, oops_timestamp) && + !time_after(jiffies, oops_timestamp + 30 * HZ)) + return; + + oops_timestamp = jiffies; + + debug_locks_off(); + /* If a crash is occurring, make sure we can't deadlock */ + raw_spin_lock_init(&logbuf_lock); + /* And make sure that we print immediately */ + sema_init(&console_sem, 1); +} + +/* Check if we have any console registered that can be called early in boot. */ +static int have_callable_console(void) +{ + struct console *con; + + for_each_console(con) + if (con->flags & CON_ANYTIME) + return 1; + + return 0; +} + +/* + * Can we actually use the console at this time on this cpu? + * + * Console drivers may assume that per-cpu resources have + * been allocated. So unless they're explicitly marked as + * being able to cope (CON_ANYTIME) don't call them until + * this CPU is officially up. + */ +static inline int can_use_console(unsigned int cpu) +{ + return cpu_online(cpu) || have_callable_console(); +} + +/* + * Try to get console ownership to actually show the kernel + * messages from a 'printk'. Return true (and with the + * console_lock held, and 'console_locked' set) if it + * is successful, false otherwise. + * + * This gets called with the 'logbuf_lock' spinlock held and + * interrupts disabled. It should return with 'lockbuf_lock' + * released but interrupts still disabled. + */ +static int console_trylock_for_printk(unsigned int cpu) + __releases(&logbuf_lock) +{ + int retval = 0, wake = 0; + + if (console_trylock()) { + retval = 1; + + /* + * If we can't use the console, we need to release + * the console semaphore by hand to avoid flushing + * the buffer. We need to hold the console semaphore + * in order to do this test safely. + */ + if (!can_use_console(cpu)) { + console_locked = 0; + wake = 1; + retval = 0; + } + } + logbuf_cpu = UINT_MAX; + raw_spin_unlock(&logbuf_lock); + if (wake) + up(&console_sem); + return retval; +} + +int printk_delay_msec __read_mostly; + +static inline void printk_delay(void) +{ + if (unlikely(printk_delay_msec)) { + int m = printk_delay_msec; + + while (m--) { + mdelay(1); + touch_nmi_watchdog(); + } + } +} + +/* + * Continuation lines are buffered, and not committed to the record buffer + * until the line is complete, or a race forces it. The line fragments + * though, are printed immediately to the consoles to ensure everything has + * reached the console in case of a kernel crash. + */ +static struct cont { + char buf[LOG_LINE_MAX]; + size_t len; /* length == 0 means unused buffer */ + size_t cons; /* bytes written to console */ + struct task_struct *owner; /* task of first print*/ + u64 ts_nsec; /* time of first print */ + u8 level; /* log level of first message */ + u8 facility; /* log level of first message */ + enum log_flags flags; /* prefix, newline flags */ + bool flushed:1; /* buffer sealed and committed */ +} cont; + +static void cont_flush(enum log_flags flags) +{ + if (cont.flushed) + return; + if (cont.len == 0) + return; + + if (cont.cons) { + /* + * If a fragment of this line was directly flushed to the + * console; wait for the console to pick up the rest of the + * line. LOG_NOCONS suppresses a duplicated output. + */ + log_store(cont.facility, cont.level, flags | LOG_NOCONS, + cont.ts_nsec, NULL, 0, cont.buf, cont.len); + cont.flags = flags; + cont.flushed = true; + } else { + /* + * If no fragment of this line ever reached the console, + * just submit it to the store and free the buffer. + */ + log_store(cont.facility, cont.level, flags, 0, + NULL, 0, cont.buf, cont.len); + cont.len = 0; + } +} + +static bool cont_add(int facility, int level, const char *text, size_t len) +{ + if (cont.len && cont.flushed) + return false; + + if (cont.len + len > sizeof(cont.buf)) { + /* the line gets too long, split it up in separate records */ + cont_flush(LOG_CONT); + return false; + } + + if (!cont.len) { + cont.facility = facility; + cont.level = level; + cont.owner = current; + cont.ts_nsec = local_clock(); + cont.flags = 0; + cont.cons = 0; + cont.flushed = false; + } + + memcpy(cont.buf + cont.len, text, len); + cont.len += len; + + if (cont.len > (sizeof(cont.buf) * 80) / 100) + cont_flush(LOG_CONT); + + return true; +} + +static size_t cont_print_text(char *text, size_t size) +{ + size_t textlen = 0; + size_t len; + + if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) { + textlen += print_time(cont.ts_nsec, text); + size -= textlen; + } + + len = cont.len - cont.cons; + if (len > 0) { + if (len+1 > size) + len = size-1; + memcpy(text + textlen, cont.buf + cont.cons, len); + textlen += len; + cont.cons = cont.len; + } + + if (cont.flushed) { + if (cont.flags & LOG_NEWLINE) + text[textlen++] = '\n'; + /* got everything, release buffer */ + cont.len = 0; + } + return textlen; +} + +asmlinkage int vprintk_emit(int facility, int level, + const char *dict, size_t dictlen, + const char *fmt, va_list args) +{ + static int recursion_bug; + static char textbuf[LOG_LINE_MAX]; + char *text = textbuf; + size_t text_len; + enum log_flags lflags = 0; + unsigned long flags; + int this_cpu; + int printed_len = 0; + + boot_delay_msec(level); + printk_delay(); + + /* This stops the holder of console_sem just where we want him */ + local_irq_save(flags); + this_cpu = smp_processor_id(); + + /* + * Ouch, printk recursed into itself! + */ + if (unlikely(logbuf_cpu == this_cpu)) { + /* + * If a crash is occurring during printk() on this CPU, + * then try to get the crash message out but make sure + * we can't deadlock. Otherwise just return to avoid the + * recursion and return - but flag the recursion so that + * it can be printed at the next appropriate moment: + */ + if (!oops_in_progress && !lockdep_recursing(current)) { + recursion_bug = 1; + goto out_restore_irqs; + } + zap_locks(); + } + + lockdep_off(); + raw_spin_lock(&logbuf_lock); + logbuf_cpu = this_cpu; + + if (recursion_bug) { + static const char recursion_msg[] = + "BUG: recent printk recursion!"; + + recursion_bug = 0; + printed_len += strlen(recursion_msg); + /* emit KERN_CRIT message */ + log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, + NULL, 0, recursion_msg, printed_len); + } + + /* + * The printf needs to come first; we need the syslog + * prefix which might be passed-in as a parameter. + */ + text_len = vscnprintf(text, sizeof(textbuf), fmt, args); + + /* mark and strip a trailing newline */ + if (text_len && text[text_len-1] == '\n') { + text_len--; + lflags |= LOG_NEWLINE; + } + + /* strip kernel syslog prefix and extract log level or control flags */ + if (facility == 0) { + int kern_level = printk_get_level(text); + + if (kern_level) { + const char *end_of_header = printk_skip_level(text); + switch (kern_level) { + case '0' ... '7': + if (level == -1) + level = kern_level - '0'; + case 'd': /* KERN_DEFAULT */ + lflags |= LOG_PREFIX; + case 'c': /* KERN_CONT */ + break; + } + text_len -= end_of_header - text; + text = (char *)end_of_header; + } + } + + if (level == -1) + level = default_message_loglevel; + + if (dict) + lflags |= LOG_PREFIX|LOG_NEWLINE; + + if (!(lflags & LOG_NEWLINE)) { + /* + * Flush the conflicting buffer. An earlier newline was missing, + * or another task also prints continuation lines. + */ + if (cont.len && (lflags & LOG_PREFIX || cont.owner != current)) + cont_flush(LOG_NEWLINE); + + /* buffer line if possible, otherwise store it right away */ + if (!cont_add(facility, level, text, text_len)) + log_store(facility, level, lflags | LOG_CONT, 0, + dict, dictlen, text, text_len); + } else { + bool stored = false; + + /* + * If an earlier newline was missing and it was the same task, + * either merge it with the current buffer and flush, or if + * there was a race with interrupts (prefix == true) then just + * flush it out and store this line separately. + */ + if (cont.len && cont.owner == current) { + if (!(lflags & LOG_PREFIX)) + stored = cont_add(facility, level, text, text_len); + cont_flush(LOG_NEWLINE); + } + + if (!stored) + log_store(facility, level, lflags, 0, + dict, dictlen, text, text_len); + } + printed_len += text_len; + + /* + * Try to acquire and then immediately release the console semaphore. + * The release will print out buffers and wake up /dev/kmsg and syslog() + * users. + * + * The console_trylock_for_printk() function will release 'logbuf_lock' + * regardless of whether it actually gets the console semaphore or not. + */ + if (console_trylock_for_printk(this_cpu)) + console_unlock(); + + lockdep_on(); +out_restore_irqs: + local_irq_restore(flags); + + return printed_len; +} +EXPORT_SYMBOL(vprintk_emit); + +asmlinkage int vprintk(const char *fmt, va_list args) +{ + return vprintk_emit(0, -1, NULL, 0, fmt, args); +} +EXPORT_SYMBOL(vprintk); + +asmlinkage int printk_emit(int facility, int level, + const char *dict, size_t dictlen, + const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + r = vprintk_emit(facility, level, dict, dictlen, fmt, args); + va_end(args); + + return r; +} +EXPORT_SYMBOL(printk_emit); + +/** + * printk - print a kernel message + * @fmt: format string + * + * This is printk(). It can be called from any context. We want it to work. + * + * We try to grab the console_lock. If we succeed, it's easy - we log the + * output and call the console drivers. If we fail to get the semaphore, we + * place the output into the log buffer and return. The current holder of + * the console_sem will notice the new output in console_unlock(); and will + * send it to the consoles before releasing the lock. + * + * One effect of this deferred printing is that code which calls printk() and + * then changes console_loglevel may break. This is because console_loglevel + * is inspected when the actual printing occurs. + * + * See also: + * printf(3) + * + * See the vsnprintf() documentation for format string extensions over C99. + */ +asmlinkage int printk(const char *fmt, ...) +{ + va_list args; + int r; + +#ifdef CONFIG_KGDB_KDB + if (unlikely(kdb_trap_printk)) { + va_start(args, fmt); + r = vkdb_printf(fmt, args); + va_end(args); + return r; + } +#endif + va_start(args, fmt); + r = vprintk_emit(0, -1, NULL, 0, fmt, args); + va_end(args); + + return r; +} +EXPORT_SYMBOL(printk); + +#else /* CONFIG_PRINTK */ + +#define LOG_LINE_MAX 0 +#define PREFIX_MAX 0 +#define LOG_LINE_MAX 0 +static u64 syslog_seq; +static u32 syslog_idx; +static u64 console_seq; +static u32 console_idx; +static enum log_flags syslog_prev; +static u64 log_first_seq; +static u32 log_first_idx; +static u64 log_next_seq; +static enum log_flags console_prev; +static struct cont { + size_t len; + size_t cons; + u8 level; + bool flushed:1; +} cont; +static struct log *log_from_idx(u32 idx) { return NULL; } +static u32 log_next(u32 idx) { return 0; } +static void call_console_drivers(int level, const char *text, size_t len) {} +static size_t msg_print_text(const struct log *msg, enum log_flags prev, + bool syslog, char *buf, size_t size) { return 0; } +static size_t cont_print_text(char *text, size_t size) { return 0; } + +#endif /* CONFIG_PRINTK */ + +#ifdef CONFIG_EARLY_PRINTK +struct console *early_console; + +void early_vprintk(const char *fmt, va_list ap) +{ + if (early_console) { + char buf[512]; + int n = vscnprintf(buf, sizeof(buf), fmt, ap); + + early_console->write(early_console, buf, n); + } +} + +asmlinkage void early_printk(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + early_vprintk(fmt, ap); + va_end(ap); +} +#endif + +static int __add_preferred_console(char *name, int idx, char *options, + char *brl_options) +{ + struct console_cmdline *c; + int i; + + /* + * See if this tty is not yet registered, and + * if we have a slot free. + */ + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) + if (strcmp(console_cmdline[i].name, name) == 0 && + console_cmdline[i].index == idx) { + if (!brl_options) + selected_console = i; + return 0; + } + if (i == MAX_CMDLINECONSOLES) + return -E2BIG; + if (!brl_options) + selected_console = i; + c = &console_cmdline[i]; + strlcpy(c->name, name, sizeof(c->name)); + c->options = options; +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + c->brl_options = brl_options; +#endif + c->index = idx; + return 0; +} +/* + * Set up a list of consoles. Called from init/main.c + */ +static int __init console_setup(char *str) +{ + char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */ + char *s, *options, *brl_options = NULL; + int idx; + +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + if (!memcmp(str, "brl,", 4)) { + brl_options = ""; + str += 4; + } else if (!memcmp(str, "brl=", 4)) { + brl_options = str + 4; + str = strchr(brl_options, ','); + if (!str) { + printk(KERN_ERR "need port name after brl=\n"); + return 1; + } + *(str++) = 0; + } +#endif + + /* + * Decode str into name, index, options. + */ + if (str[0] >= '0' && str[0] <= '9') { + strcpy(buf, "ttyS"); + strncpy(buf + 4, str, sizeof(buf) - 5); + } else { + strncpy(buf, str, sizeof(buf) - 1); + } + buf[sizeof(buf) - 1] = 0; + if ((options = strchr(str, ',')) != NULL) + *(options++) = 0; +#ifdef __sparc__ + if (!strcmp(str, "ttya")) + strcpy(buf, "ttyS0"); + if (!strcmp(str, "ttyb")) + strcpy(buf, "ttyS1"); +#endif + for (s = buf; *s; s++) + if ((*s >= '0' && *s <= '9') || *s == ',') + break; + idx = simple_strtoul(s, NULL, 10); + *s = 0; + + __add_preferred_console(buf, idx, options, brl_options); + console_set_on_cmdline = 1; + return 1; +} +__setup("console=", console_setup); + +/** + * add_preferred_console - add a device to the list of preferred consoles. + * @name: device name + * @idx: device index + * @options: options for this console + * + * The last preferred console added will be used for kernel messages + * and stdin/out/err for init. Normally this is used by console_setup + * above to handle user-supplied console arguments; however it can also + * be used by arch-specific code either to override the user or more + * commonly to provide a default console (ie from PROM variables) when + * the user has not supplied one. + */ +int add_preferred_console(char *name, int idx, char *options) +{ + return __add_preferred_console(name, idx, options, NULL); +} + +int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options) +{ + struct console_cmdline *c; + int i; + + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) + if (strcmp(console_cmdline[i].name, name) == 0 && + console_cmdline[i].index == idx) { + c = &console_cmdline[i]; + strlcpy(c->name, name_new, sizeof(c->name)); + c->name[sizeof(c->name) - 1] = 0; + c->options = options; + c->index = idx_new; + return i; + } + /* not found */ + return -1; +} + +bool console_suspend_enabled = 1; +EXPORT_SYMBOL(console_suspend_enabled); + +static int __init console_suspend_disable(char *str) +{ + console_suspend_enabled = 0; + return 1; +} +__setup("no_console_suspend", console_suspend_disable); +module_param_named(console_suspend, console_suspend_enabled, + bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(console_suspend, "suspend console during suspend" + " and hibernate operations"); + +/** + * suspend_console - suspend the console subsystem + * + * This disables printk() while we go into suspend states + */ +void suspend_console(void) +{ + if (!console_suspend_enabled) + return; + printk("Suspending console(s) (use no_console_suspend to debug)\n"); + console_lock(); + console_suspended = 1; + up(&console_sem); +} + +void resume_console(void) +{ + if (!console_suspend_enabled) + return; + down(&console_sem); + console_suspended = 0; + console_unlock(); +} + +/** + * console_cpu_notify - print deferred console messages after CPU hotplug + * @self: notifier struct + * @action: CPU hotplug event + * @hcpu: unused + * + * If printk() is called from a CPU that is not online yet, the messages + * will be spooled but will not show up on the console. This function is + * called when a new CPU comes online (or fails to come up), and ensures + * that any such output gets printed. + */ +static int console_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_ONLINE: + case CPU_DEAD: + case CPU_DOWN_FAILED: + case CPU_UP_CANCELED: + console_lock(); + console_unlock(); + } + return NOTIFY_OK; +} + +/** + * console_lock - lock the console system for exclusive use. + * + * Acquires a lock which guarantees that the caller has + * exclusive access to the console system and the console_drivers list. + * + * Can sleep, returns nothing. + */ +void console_lock(void) +{ + might_sleep(); + + down(&console_sem); + if (console_suspended) + return; + console_locked = 1; + console_may_schedule = 1; + mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_); +} +EXPORT_SYMBOL(console_lock); + +/** + * console_trylock - try to lock the console system for exclusive use. + * + * Tried to acquire a lock which guarantees that the caller has + * exclusive access to the console system and the console_drivers list. + * + * returns 1 on success, and 0 on failure to acquire the lock. + */ +int console_trylock(void) +{ + if (down_trylock(&console_sem)) + return 0; + if (console_suspended) { + up(&console_sem); + return 0; + } + console_locked = 1; + console_may_schedule = 0; + mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_); + return 1; +} +EXPORT_SYMBOL(console_trylock); + +int is_console_locked(void) +{ + return console_locked; +} + +static void console_cont_flush(char *text, size_t size) +{ + unsigned long flags; + size_t len; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + + if (!cont.len) + goto out; + + /* + * We still queue earlier records, likely because the console was + * busy. The earlier ones need to be printed before this one, we + * did not flush any fragment so far, so just let it queue up. + */ + if (console_seq < log_next_seq && !cont.cons) + goto out; + + len = cont_print_text(text, size); + raw_spin_unlock(&logbuf_lock); + stop_critical_timings(); + call_console_drivers(cont.level, text, len); + start_critical_timings(); + local_irq_restore(flags); + return; +out: + raw_spin_unlock_irqrestore(&logbuf_lock, flags); +} + +/** + * console_unlock - unlock the console system + * + * Releases the console_lock which the caller holds on the console system + * and the console driver list. + * + * While the console_lock was held, console output may have been buffered + * by printk(). If this is the case, console_unlock(); emits + * the output prior to releasing the lock. + * + * If there is output waiting, we wake /dev/kmsg and syslog() users. + * + * console_unlock(); may be called from any context. + */ +void console_unlock(void) +{ + static char text[LOG_LINE_MAX + PREFIX_MAX]; + static u64 seen_seq; + unsigned long flags; + bool wake_klogd = false; + bool retry; + + if (console_suspended) { + up(&console_sem); + return; + } + + console_may_schedule = 0; + + /* flush buffered message fragment immediately to console */ + console_cont_flush(text, sizeof(text)); +again: + for (;;) { + struct log *msg; + size_t len; + int level; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + if (seen_seq != log_next_seq) { + wake_klogd = true; + seen_seq = log_next_seq; + } + + if (console_seq < log_first_seq) { + /* messages are gone, move to first one */ + console_seq = log_first_seq; + console_idx = log_first_idx; + console_prev = 0; + } +skip: + if (console_seq == log_next_seq) + break; + + msg = log_from_idx(console_idx); + if (msg->flags & LOG_NOCONS) { + /* + * Skip record we have buffered and already printed + * directly to the console when we received it. + */ + console_idx = log_next(console_idx); + console_seq++; + /* + * We will get here again when we register a new + * CON_PRINTBUFFER console. Clear the flag so we + * will properly dump everything later. + */ + msg->flags &= ~LOG_NOCONS; + console_prev = msg->flags; + goto skip; + } + + level = msg->level; + len = msg_print_text(msg, console_prev, false, + text, sizeof(text)); + console_idx = log_next(console_idx); + console_seq++; + console_prev = msg->flags; + raw_spin_unlock(&logbuf_lock); + + stop_critical_timings(); /* don't trace print latency */ + call_console_drivers(level, text, len); + start_critical_timings(); + local_irq_restore(flags); + } + console_locked = 0; + mutex_release(&console_lock_dep_map, 1, _RET_IP_); + + /* Release the exclusive_console once it is used */ + if (unlikely(exclusive_console)) + exclusive_console = NULL; + + raw_spin_unlock(&logbuf_lock); + + up(&console_sem); + + /* + * Someone could have filled up the buffer again, so re-check if there's + * something to flush. In case we cannot trylock the console_sem again, + * there's a new owner and the console_unlock() from them will do the + * flush, no worries. + */ + raw_spin_lock(&logbuf_lock); + retry = console_seq != log_next_seq; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + + if (retry && console_trylock()) + goto again; + + if (wake_klogd) + wake_up_klogd(); +} +EXPORT_SYMBOL(console_unlock); + +/** + * console_conditional_schedule - yield the CPU if required + * + * If the console code is currently allowed to sleep, and + * if this CPU should yield the CPU to another task, do + * so here. + * + * Must be called within console_lock();. + */ +void __sched console_conditional_schedule(void) +{ + if (console_may_schedule) + cond_resched(); +} +EXPORT_SYMBOL(console_conditional_schedule); + +void console_unblank(void) +{ + struct console *c; + + /* + * console_unblank can no longer be called in interrupt context unless + * oops_in_progress is set to 1.. + */ + if (oops_in_progress) { + if (down_trylock(&console_sem) != 0) + return; + } else + console_lock(); + + console_locked = 1; + console_may_schedule = 0; + for_each_console(c) + if ((c->flags & CON_ENABLED) && c->unblank) + c->unblank(); + console_unlock(); +} + +/* + * Return the console tty driver structure and its associated index + */ +struct tty_driver *console_device(int *index) +{ + struct console *c; + struct tty_driver *driver = NULL; + + console_lock(); + for_each_console(c) { + if (!c->device) + continue; + driver = c->device(c, index); + if (driver) + break; + } + console_unlock(); + return driver; +} + +/* + * Prevent further output on the passed console device so that (for example) + * serial drivers can disable console output before suspending a port, and can + * re-enable output afterwards. + */ +void console_stop(struct console *console) +{ + console_lock(); + console->flags &= ~CON_ENABLED; + console_unlock(); +} +EXPORT_SYMBOL(console_stop); + +void console_start(struct console *console) +{ + console_lock(); + console->flags |= CON_ENABLED; + console_unlock(); +} +EXPORT_SYMBOL(console_start); + +static int __read_mostly keep_bootcon; + +static int __init keep_bootcon_setup(char *str) +{ + keep_bootcon = 1; + printk(KERN_INFO "debug: skip boot console de-registration.\n"); + + return 0; +} + +early_param("keep_bootcon", keep_bootcon_setup); + +/* + * The console driver calls this routine during kernel initialization + * to register the console printing procedure with printk() and to + * print any messages that were printed by the kernel before the + * console driver was initialized. + * + * This can happen pretty early during the boot process (because of + * early_printk) - sometimes before setup_arch() completes - be careful + * of what kernel features are used - they may not be initialised yet. + * + * There are two types of consoles - bootconsoles (early_printk) and + * "real" consoles (everything which is not a bootconsole) which are + * handled differently. + * - Any number of bootconsoles can be registered at any time. + * - As soon as a "real" console is registered, all bootconsoles + * will be unregistered automatically. + * - Once a "real" console is registered, any attempt to register a + * bootconsoles will be rejected + */ +void register_console(struct console *newcon) +{ + int i; + unsigned long flags; + struct console *bcon = NULL; + + /* + * before we register a new CON_BOOT console, make sure we don't + * already have a valid console + */ + if (console_drivers && newcon->flags & CON_BOOT) { + /* find the last or real console */ + for_each_console(bcon) { + if (!(bcon->flags & CON_BOOT)) { + printk(KERN_INFO "Too late to register bootconsole %s%d\n", + newcon->name, newcon->index); + return; + } + } + } + + if (console_drivers && console_drivers->flags & CON_BOOT) + bcon = console_drivers; + + if (preferred_console < 0 || bcon || !console_drivers) + preferred_console = selected_console; + + if (newcon->early_setup) + newcon->early_setup(); + + /* + * See if we want to use this console driver. If we + * didn't select a console we take the first one + * that registers here. + */ + if (preferred_console < 0) { + if (newcon->index < 0) + newcon->index = 0; + if (newcon->setup == NULL || + newcon->setup(newcon, NULL) == 0) { + newcon->flags |= CON_ENABLED; + if (newcon->device) { + newcon->flags |= CON_CONSDEV; + preferred_console = 0; + } + } + } + + /* + * See if this console matches one we selected on + * the command line. + */ + for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; + i++) { + if (strcmp(console_cmdline[i].name, newcon->name) != 0) + continue; + if (newcon->index >= 0 && + newcon->index != console_cmdline[i].index) + continue; + if (newcon->index < 0) + newcon->index = console_cmdline[i].index; +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + if (console_cmdline[i].brl_options) { + newcon->flags |= CON_BRL; + braille_register_console(newcon, + console_cmdline[i].index, + console_cmdline[i].options, + console_cmdline[i].brl_options); + return; + } +#endif + if (newcon->setup && + newcon->setup(newcon, console_cmdline[i].options) != 0) + break; + newcon->flags |= CON_ENABLED; + newcon->index = console_cmdline[i].index; + if (i == selected_console) { + newcon->flags |= CON_CONSDEV; + preferred_console = selected_console; + } + break; + } + + if (!(newcon->flags & CON_ENABLED)) + return; + + /* + * If we have a bootconsole, and are switching to a real console, + * don't print everything out again, since when the boot console, and + * the real console are the same physical device, it's annoying to + * see the beginning boot messages twice + */ + if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) + newcon->flags &= ~CON_PRINTBUFFER; + + /* + * Put this console in the list - keep the + * preferred driver at the head of the list. + */ + console_lock(); + if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { + newcon->next = console_drivers; + console_drivers = newcon; + if (newcon->next) + newcon->next->flags &= ~CON_CONSDEV; + } else { + newcon->next = console_drivers->next; + console_drivers->next = newcon; + } + if (newcon->flags & CON_PRINTBUFFER) { + /* + * console_unlock(); will print out the buffered messages + * for us. + */ + raw_spin_lock_irqsave(&logbuf_lock, flags); + console_seq = syslog_seq; + console_idx = syslog_idx; + console_prev = syslog_prev; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + /* + * We're about to replay the log buffer. Only do this to the + * just-registered console to avoid excessive message spam to + * the already-registered consoles. + */ + exclusive_console = newcon; + } + console_unlock(); + console_sysfs_notify(); + + /* + * By unregistering the bootconsoles after we enable the real console + * we get the "console xxx enabled" message on all the consoles - + * boot consoles, real consoles, etc - this is to ensure that end + * users know there might be something in the kernel's log buffer that + * went to the bootconsole (that they do not see on the real console) + */ + if (bcon && + ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && + !keep_bootcon) { + /* we need to iterate through twice, to make sure we print + * everything out, before we unregister the console(s) + */ + printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", + newcon->name, newcon->index); + for_each_console(bcon) + if (bcon->flags & CON_BOOT) + unregister_console(bcon); + } else { + printk(KERN_INFO "%sconsole [%s%d] enabled\n", + (newcon->flags & CON_BOOT) ? "boot" : "" , + newcon->name, newcon->index); + } +} +EXPORT_SYMBOL(register_console); + +int unregister_console(struct console *console) +{ + struct console *a, *b; + int res = 1; + +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + if (console->flags & CON_BRL) + return braille_unregister_console(console); +#endif + + console_lock(); + if (console_drivers == console) { + console_drivers=console->next; + res = 0; + } else if (console_drivers) { + for (a=console_drivers->next, b=console_drivers ; + a; b=a, a=b->next) { + if (a == console) { + b->next = a->next; + res = 0; + break; + } + } + } + + /* + * If this isn't the last console and it has CON_CONSDEV set, we + * need to set it on the next preferred console. + */ + if (console_drivers != NULL && console->flags & CON_CONSDEV) + console_drivers->flags |= CON_CONSDEV; + + console_unlock(); + console_sysfs_notify(); + return res; +} +EXPORT_SYMBOL(unregister_console); + +static int __init printk_late_init(void) +{ + struct console *con; + + for_each_console(con) { + if (!keep_bootcon && con->flags & CON_BOOT) { + printk(KERN_INFO "turn off boot console %s%d\n", + con->name, con->index); + unregister_console(con); + } + } + hotcpu_notifier(console_cpu_notify, 0); + return 0; +} +late_initcall(printk_late_init); + +#if defined CONFIG_PRINTK +/* + * Delayed printk version, for scheduler-internal messages: + */ +#define PRINTK_BUF_SIZE 512 + +#define PRINTK_PENDING_WAKEUP 0x01 +#define PRINTK_PENDING_SCHED 0x02 + +static DEFINE_PER_CPU(int, printk_pending); +static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf); + +static void wake_up_klogd_work_func(struct irq_work *irq_work) +{ + int pending = __this_cpu_xchg(printk_pending, 0); + + if (pending & PRINTK_PENDING_SCHED) { + char *buf = __get_cpu_var(printk_sched_buf); + printk(KERN_WARNING "[sched_delayed] %s", buf); + } + + if (pending & PRINTK_PENDING_WAKEUP) + wake_up_interruptible(&log_wait); +} + +static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { + .func = wake_up_klogd_work_func, + .flags = IRQ_WORK_LAZY, +}; + +void wake_up_klogd(void) +{ + preempt_disable(); + if (waitqueue_active(&log_wait)) { + this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); + irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); + } + preempt_enable(); +} + +int printk_sched(const char *fmt, ...) +{ + unsigned long flags; + va_list args; + char *buf; + int r; + + local_irq_save(flags); + buf = __get_cpu_var(printk_sched_buf); + + va_start(args, fmt); + r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args); + va_end(args); + + __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED); + irq_work_queue(&__get_cpu_var(wake_up_klogd_work)); + local_irq_restore(flags); + + return r; +} + +/* + * printk rate limiting, lifted from the networking subsystem. + * + * This enforces a rate limit: not more than 10 kernel messages + * every 5s to make a denial-of-service attack impossible. + */ +DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); + +int __printk_ratelimit(const char *func) +{ + return ___ratelimit(&printk_ratelimit_state, func); +} +EXPORT_SYMBOL(__printk_ratelimit); + +/** + * printk_timed_ratelimit - caller-controlled printk ratelimiting + * @caller_jiffies: pointer to caller's state + * @interval_msecs: minimum interval between prints + * + * printk_timed_ratelimit() returns true if more than @interval_msecs + * milliseconds have elapsed since the last time printk_timed_ratelimit() + * returned true. + */ +bool printk_timed_ratelimit(unsigned long *caller_jiffies, + unsigned int interval_msecs) +{ + if (*caller_jiffies == 0 + || !time_in_range(jiffies, *caller_jiffies, + *caller_jiffies + + msecs_to_jiffies(interval_msecs))) { + *caller_jiffies = jiffies; + return true; + } + return false; +} +EXPORT_SYMBOL(printk_timed_ratelimit); + +static DEFINE_SPINLOCK(dump_list_lock); +static LIST_HEAD(dump_list); + +/** + * kmsg_dump_register - register a kernel log dumper. + * @dumper: pointer to the kmsg_dumper structure + * + * Adds a kernel log dumper to the system. The dump callback in the + * structure will be called when the kernel oopses or panics and must be + * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. + */ +int kmsg_dump_register(struct kmsg_dumper *dumper) +{ + unsigned long flags; + int err = -EBUSY; + + /* The dump callback needs to be set */ + if (!dumper->dump) + return -EINVAL; + + spin_lock_irqsave(&dump_list_lock, flags); + /* Don't allow registering multiple times */ + if (!dumper->registered) { + dumper->registered = 1; + list_add_tail_rcu(&dumper->list, &dump_list); + err = 0; + } + spin_unlock_irqrestore(&dump_list_lock, flags); + + return err; +} +EXPORT_SYMBOL_GPL(kmsg_dump_register); + +/** + * kmsg_dump_unregister - unregister a kmsg dumper. + * @dumper: pointer to the kmsg_dumper structure + * + * Removes a dump device from the system. Returns zero on success and + * %-EINVAL otherwise. + */ +int kmsg_dump_unregister(struct kmsg_dumper *dumper) +{ + unsigned long flags; + int err = -EINVAL; + + spin_lock_irqsave(&dump_list_lock, flags); + if (dumper->registered) { + dumper->registered = 0; + list_del_rcu(&dumper->list); + err = 0; + } + spin_unlock_irqrestore(&dump_list_lock, flags); + synchronize_rcu(); + + return err; +} +EXPORT_SYMBOL_GPL(kmsg_dump_unregister); + +static bool always_kmsg_dump; +module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); + +/** + * kmsg_dump - dump kernel log to kernel message dumpers. + * @reason: the reason (oops, panic etc) for dumping + * + * Call each of the registered dumper's dump() callback, which can + * retrieve the kmsg records with kmsg_dump_get_line() or + * kmsg_dump_get_buffer(). + */ +void kmsg_dump(enum kmsg_dump_reason reason) +{ + struct kmsg_dumper *dumper; + unsigned long flags; + + if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(dumper, &dump_list, list) { + if (dumper->max_reason && reason > dumper->max_reason) + continue; + + /* initialize iterator with data about the stored records */ + dumper->active = true; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + dumper->cur_seq = clear_seq; + dumper->cur_idx = clear_idx; + dumper->next_seq = log_next_seq; + dumper->next_idx = log_next_idx; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + + /* invoke dumper which will iterate over records */ + dumper->dump(dumper, reason); + + /* reset iterator */ + dumper->active = false; + } + rcu_read_unlock(); +} + +/** + * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @line: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the beginning of the kmsg buffer, with the oldest kmsg + * record, and copy one record into the provided buffer. + * + * Consecutive calls will return the next available record moving + * towards the end of the buffer with the youngest messages. + * + * A return value of FALSE indicates that there are no more records to + * read. + * + * The function is similar to kmsg_dump_get_line(), but grabs no locks. + */ +bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, + char *line, size_t size, size_t *len) +{ + struct log *msg; + size_t l = 0; + bool ret = false; + + if (!dumper->active) + goto out; + + if (dumper->cur_seq < log_first_seq) { + /* messages are gone, move to first available one */ + dumper->cur_seq = log_first_seq; + dumper->cur_idx = log_first_idx; + } + + /* last entry */ + if (dumper->cur_seq >= log_next_seq) + goto out; + + msg = log_from_idx(dumper->cur_idx); + l = msg_print_text(msg, 0, syslog, line, size); + + dumper->cur_idx = log_next(dumper->cur_idx); + dumper->cur_seq++; + ret = true; +out: + if (len) + *len = l; + return ret; +} + +/** + * kmsg_dump_get_line - retrieve one kmsg log line + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @line: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the beginning of the kmsg buffer, with the oldest kmsg + * record, and copy one record into the provided buffer. + * + * Consecutive calls will return the next available record moving + * towards the end of the buffer with the youngest messages. + * + * A return value of FALSE indicates that there are no more records to + * read. + */ +bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, + char *line, size_t size, size_t *len) +{ + unsigned long flags; + bool ret; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(kmsg_dump_get_line); + +/** + * kmsg_dump_get_buffer - copy kmsg log lines + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @buf: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the end of the kmsg buffer and fill the provided buffer + * with as many of the the *youngest* kmsg records that fit into it. + * If the buffer is large enough, all available kmsg records will be + * copied with a single call. + * + * Consecutive calls will fill the buffer with the next block of + * available older records, not including the earlier retrieved ones. + * + * A return value of FALSE indicates that there are no more records to + * read. + */ +bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, + char *buf, size_t size, size_t *len) +{ + unsigned long flags; + u64 seq; + u32 idx; + u64 next_seq; + u32 next_idx; + enum log_flags prev; + size_t l = 0; + bool ret = false; + + if (!dumper->active) + goto out; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + if (dumper->cur_seq < log_first_seq) { + /* messages are gone, move to first available one */ + dumper->cur_seq = log_first_seq; + dumper->cur_idx = log_first_idx; + } + + /* last entry */ + if (dumper->cur_seq >= dumper->next_seq) { + raw_spin_unlock_irqrestore(&logbuf_lock, flags); + goto out; + } + + /* calculate length of entire buffer */ + seq = dumper->cur_seq; + idx = dumper->cur_idx; + prev = 0; + while (seq < dumper->next_seq) { + struct log *msg = log_from_idx(idx); + + l += msg_print_text(msg, prev, true, NULL, 0); + idx = log_next(idx); + seq++; + prev = msg->flags; + } + + /* move first record forward until length fits into the buffer */ + seq = dumper->cur_seq; + idx = dumper->cur_idx; + prev = 0; + while (l > size && seq < dumper->next_seq) { + struct log *msg = log_from_idx(idx); + + l -= msg_print_text(msg, prev, true, NULL, 0); + idx = log_next(idx); + seq++; + prev = msg->flags; + } + + /* last message in next interation */ + next_seq = seq; + next_idx = idx; + + l = 0; + prev = 0; + while (seq < dumper->next_seq) { + struct log *msg = log_from_idx(idx); + + l += msg_print_text(msg, prev, syslog, buf + l, size - l); + idx = log_next(idx); + seq++; + prev = msg->flags; + } + + dumper->next_seq = next_seq; + dumper->next_idx = next_idx; + ret = true; + raw_spin_unlock_irqrestore(&logbuf_lock, flags); +out: + if (len) + *len = l; + return ret; +} +EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); + +/** + * kmsg_dump_rewind_nolock - reset the interator (unlocked version) + * @dumper: registered kmsg dumper + * + * Reset the dumper's iterator so that kmsg_dump_get_line() and + * kmsg_dump_get_buffer() can be called again and used multiple + * times within the same dumper.dump() callback. + * + * The function is similar to kmsg_dump_rewind(), but grabs no locks. + */ +void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) +{ + dumper->cur_seq = clear_seq; + dumper->cur_idx = clear_idx; + dumper->next_seq = log_next_seq; + dumper->next_idx = log_next_idx; +} + +/** + * kmsg_dump_rewind - reset the interator + * @dumper: registered kmsg dumper + * + * Reset the dumper's iterator so that kmsg_dump_get_line() and + * kmsg_dump_get_buffer() can be called again and used multiple + * times within the same dumper.dump() callback. + */ +void kmsg_dump_rewind(struct kmsg_dumper *dumper) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&logbuf_lock, flags); + kmsg_dump_rewind_nolock(dumper); + raw_spin_unlock_irqrestore(&logbuf_lock, flags); +} +EXPORT_SYMBOL_GPL(kmsg_dump_rewind); + +static char dump_stack_arch_desc_str[128]; + +/** + * dump_stack_set_arch_desc - set arch-specific str to show with task dumps + * @fmt: printf-style format string + * @...: arguments for the format string + * + * The configured string will be printed right after utsname during task + * dumps. Usually used to add arch-specific system identifiers. If an + * arch wants to make use of such an ID string, it should initialize this + * as soon as possible during boot. + */ +void __init dump_stack_set_arch_desc(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str), + fmt, args); + va_end(args); +} + +/** + * dump_stack_print_info - print generic debug info for dump_stack() + * @log_lvl: log level + * + * Arch-specific dump_stack() implementations can use this function to + * print out the same debug information as the generic dump_stack(). + */ +void dump_stack_print_info(const char *log_lvl) +{ + printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n", + log_lvl, raw_smp_processor_id(), current->pid, current->comm, + print_tainted(), init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + + if (dump_stack_arch_desc_str[0] != '\0') + printk("%sHardware name: %s\n", + log_lvl, dump_stack_arch_desc_str); + + print_worker_info(log_lvl, current); +} + +/** + * show_regs_print_info - print generic debug info for show_regs() + * @log_lvl: log level + * + * show_regs() implementations can use this function to print out generic + * debug information. + */ +void show_regs_print_info(const char *log_lvl) +{ + dump_stack_print_info(log_lvl); + + printk("%stask: %p ti: %p task.ti: %p\n", + log_lvl, current, current_thread_info(), + task_thread_info(current)); +} + +#endif -- cgit v0.10.2 From d197c43d04decb6b1298fa3ef26ea04a9ca7c977 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:44 -0700 Subject: printk: add console_cmdline.h Add an include file for the console_cmdline struct so that the braille console driver can be separated. Signed-off-by: Joe Perches Cc: Samuel Thibault Cc: Ming Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h new file mode 100644 index 0000000..cbd69d8 --- /dev/null +++ b/kernel/printk/console_cmdline.h @@ -0,0 +1,14 @@ +#ifndef _CONSOLE_CMDLINE_H +#define _CONSOLE_CMDLINE_H + +struct console_cmdline +{ + char name[8]; /* Name of the driver */ + int index; /* Minor dev. to use */ + char *options; /* Options for the driver */ +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + char *brl_options; /* Options for braille driver */ +#endif +}; + +#endif diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 69b0890..4da2b2c 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -51,6 +51,8 @@ #define CREATE_TRACE_POINTS #include +#include "console_cmdline.h" + /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL @@ -105,19 +107,11 @@ static struct console *exclusive_console; /* * Array of consoles built from command line options (console=) */ -struct console_cmdline -{ - char name[8]; /* Name of the driver */ - int index; /* Minor dev. to use */ - char *options; /* Options for the driver */ -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - char *brl_options; /* Options for braille driver */ -#endif -}; #define MAX_CMDLINECONSOLES 8 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; + static int selected_console = -1; static int preferred_console = -1; int console_set_on_cmdline; -- cgit v0.10.2 From bbeddf52adc1b4207674ab88686cbbe58c24f721 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:45 -0700 Subject: printk: move braille console support into separate braille.[ch] files Create files with prototypes and static inlines for braille support. Make braille_console functions return 1 on success. Corrected CONFIG_A11Y_BRAILLE_CONSOLE=n _braille_console_setup return value to NULL. Signed-off-by: Joe Perches Reviewed-by: Samuel Thibault Cc: Ming Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index d21167b..dc34a5b 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -359,6 +359,9 @@ int braille_register_console(struct console *console, int index, char *console_options, char *braille_options) { int ret; + + if (!(console->flags & CON_BRL)) + return 0; if (!console_options) /* Only support VisioBraille for now */ console_options = "57600o8"; @@ -374,15 +377,17 @@ int braille_register_console(struct console *console, int index, braille_co = console; register_keyboard_notifier(&keyboard_notifier_block); register_vt_notifier(&vt_notifier_block); - return 0; + return 1; } int braille_unregister_console(struct console *console) { if (braille_co != console) return -EINVAL; + if (!(console->flags & CON_BRL)) + return 0; unregister_keyboard_notifier(&keyboard_notifier_block); unregister_vt_notifier(&vt_notifier_block); braille_co = NULL; - return 0; + return 1; } diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile index 36d306d..85405bd 100644 --- a/kernel/printk/Makefile +++ b/kernel/printk/Makefile @@ -1 +1,2 @@ obj-y = printk.o +obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c new file mode 100644 index 0000000..b51087f --- /dev/null +++ b/kernel/printk/braille.c @@ -0,0 +1,48 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#include "console_cmdline.h" +#include "braille.h" + +char *_braille_console_setup(char **str, char **brl_options) +{ + if (!memcmp(*str, "brl,", 4)) { + *brl_options = ""; + *str += 4; + } else if (!memcmp(str, "brl=", 4)) { + *brl_options = *str + 4; + *str = strchr(*brl_options, ','); + if (!*str) + pr_err("need port name after brl=\n"); + else + *((*str)++) = 0; + } + + return *str; +} + +int +_braille_register_console(struct console *console, struct console_cmdline *c) +{ + int rtn = 0; + + if (c->brl_options) { + console->flags |= CON_BRL; + rtn = braille_register_console(console, c->index, c->options, + c->brl_options); + } + + return rtn; +} + +int +_braille_unregister_console(struct console *console) +{ + if (console->flags & CON_BRL) + return braille_unregister_console(console); + + return 0; +} diff --git a/kernel/printk/braille.h b/kernel/printk/braille.h new file mode 100644 index 0000000..769d771 --- /dev/null +++ b/kernel/printk/braille.h @@ -0,0 +1,48 @@ +#ifndef _PRINTK_BRAILLE_H +#define _PRINTK_BRAILLE_H + +#ifdef CONFIG_A11Y_BRAILLE_CONSOLE + +static inline void +braille_set_options(struct console_cmdline *c, char *brl_options) +{ + c->brl_options = brl_options; +} + +char * +_braille_console_setup(char **str, char **brl_options); + +int +_braille_register_console(struct console *console, struct console_cmdline *c); + +int +_braille_unregister_console(struct console *console); + +#else + +static inline void +braille_set_options(struct console_cmdline *c, char *brl_options) +{ +} + +static inline char * +_braille_console_setup(char **str, char **brl_options) +{ + return NULL; +} + +static inline int +_braille_register_console(struct console *console, struct console_cmdline *c) +{ + return 0; +} + +static inline int +_braille_unregister_console(struct console *console) +{ + return 0; +} + +#endif + +#endif diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 4da2b2c..5a022e0 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -52,6 +52,7 @@ #include #include "console_cmdline.h" +#include "braille.h" /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL @@ -1769,9 +1770,8 @@ static int __add_preferred_console(char *name, int idx, char *options, c = &console_cmdline[i]; strlcpy(c->name, name, sizeof(c->name)); c->options = options; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - c->brl_options = brl_options; -#endif + braille_set_options(c, brl_options); + c->index = idx; return 0; } @@ -1784,20 +1784,8 @@ static int __init console_setup(char *str) char *s, *options, *brl_options = NULL; int idx; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (!memcmp(str, "brl,", 4)) { - brl_options = ""; - str += 4; - } else if (!memcmp(str, "brl=", 4)) { - brl_options = str + 4; - str = strchr(brl_options, ','); - if (!str) { - printk(KERN_ERR "need port name after brl=\n"); - return 1; - } - *(str++) = 0; - } -#endif + if (_braille_console_setup(&str, &brl_options)) + return 1; /* * Decode str into name, index, options. @@ -2291,16 +2279,10 @@ void register_console(struct console *newcon) continue; if (newcon->index < 0) newcon->index = console_cmdline[i].index; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (console_cmdline[i].brl_options) { - newcon->flags |= CON_BRL; - braille_register_console(newcon, - console_cmdline[i].index, - console_cmdline[i].options, - console_cmdline[i].brl_options); + + if (_braille_register_console(newcon, &console_cmdline[i])) return; - } -#endif + if (newcon->setup && newcon->setup(newcon, console_cmdline[i].options) != 0) break; @@ -2388,13 +2370,13 @@ EXPORT_SYMBOL(register_console); int unregister_console(struct console *console) { struct console *a, *b; - int res = 1; + int res; -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - if (console->flags & CON_BRL) - return braille_unregister_console(console); -#endif + res = _braille_unregister_console(console); + if (res) + return res; + res = 1; console_lock(); if (console_drivers == console) { console_drivers=console->next; -- cgit v0.10.2 From 23475408c618ecd5b44b7e069fd65ec73d17d9f0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:46 -0700 Subject: printk: use pointer for console_cmdline indexing Make the code a bit more compact by always using a pointer for the active console_cmdline. Move overly indented code to correct indent level. Signed-off-by: Joe Perches Cc: Samuel Thibault Cc: Ming Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 5a022e0..8f1fb50 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1756,18 +1756,19 @@ static int __add_preferred_console(char *name, int idx, char *options, * See if this tty is not yet registered, and * if we have a slot free. */ - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - if (!brl_options) - selected_console = i; - return 0; + for (i = 0, c = console_cmdline; + i < MAX_CMDLINECONSOLES && c->name[0]; + i++, c++) { + if (strcmp(c->name, name) == 0 && c->index == idx) { + if (!brl_options) + selected_console = i; + return 0; } + } if (i == MAX_CMDLINECONSOLES) return -E2BIG; if (!brl_options) selected_console = i; - c = &console_cmdline[i]; strlcpy(c->name, name, sizeof(c->name)); c->options = options; braille_set_options(c, brl_options); @@ -1840,15 +1841,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha struct console_cmdline *c; int i; - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) - if (strcmp(console_cmdline[i].name, name) == 0 && - console_cmdline[i].index == idx) { - c = &console_cmdline[i]; - strlcpy(c->name, name_new, sizeof(c->name)); - c->name[sizeof(c->name) - 1] = 0; - c->options = options; - c->index = idx_new; - return i; + for (i = 0, c = console_cmdline; + i < MAX_CMDLINECONSOLES && c->name[0]; + i++, c++) + if (strcmp(c->name, name) == 0 && c->index == idx) { + strlcpy(c->name, name_new, sizeof(c->name)); + c->name[sizeof(c->name) - 1] = 0; + c->options = options; + c->index = idx_new; + return i; } /* not found */ return -1; @@ -2223,6 +2224,7 @@ void register_console(struct console *newcon) int i; unsigned long flags; struct console *bcon = NULL; + struct console_cmdline *c; /* * before we register a new CON_BOOT console, make sure we don't @@ -2270,24 +2272,25 @@ void register_console(struct console *newcon) * See if this console matches one we selected on * the command line. */ - for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; - i++) { - if (strcmp(console_cmdline[i].name, newcon->name) != 0) + for (i = 0, c = console_cmdline; + i < MAX_CMDLINECONSOLES && c->name[0]; + i++, c++) { + if (strcmp(c->name, newcon->name) != 0) continue; if (newcon->index >= 0 && - newcon->index != console_cmdline[i].index) + newcon->index != c->index) continue; if (newcon->index < 0) - newcon->index = console_cmdline[i].index; + newcon->index = c->index; - if (_braille_register_console(newcon, &console_cmdline[i])) + if (_braille_register_console(newcon, c)) return; if (newcon->setup && newcon->setup(newcon, console_cmdline[i].options) != 0) break; newcon->flags |= CON_ENABLED; - newcon->index = console_cmdline[i].index; + newcon->index = c->index; if (i == selected_console) { newcon->flags |= CON_CONSDEV; preferred_console = selected_console; -- cgit v0.10.2 From 62e32ac3505a0cab1c5ef8ea2c0eab3b26ed855f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 31 Jul 2013 13:53:47 -0700 Subject: printk: rename struct log to struct printk_log Rename the struct to enable moving portions of printk.c to separate files. The rename changes output of /proc/vmcoreinfo. Signed-off-by: Joe Perches Cc: Samuel Thibault Cc: Ming Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 8f1fb50..5b5a708 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -173,7 +173,7 @@ static int console_may_schedule; * 67 "g" * 0032 00 00 00 padding to next message header * - * The 'struct log' buffer header must never be directly exported to + * The 'struct printk_log' buffer header must never be directly exported to * userspace, it is a kernel-private implementation detail that might * need to be changed in the future, when the requirements change. * @@ -195,7 +195,7 @@ enum log_flags { LOG_CONT = 8, /* text is a fragment of a continuation line */ }; -struct log { +struct printk_log { u64 ts_nsec; /* timestamp in nanoseconds */ u16 len; /* length of entire record */ u16 text_len; /* length of text buffer */ @@ -243,7 +243,7 @@ static u32 clear_idx; #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) #define LOG_ALIGN 4 #else -#define LOG_ALIGN __alignof__(struct log) +#define LOG_ALIGN __alignof__(struct printk_log) #endif #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); @@ -254,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN; static volatile unsigned int logbuf_cpu = UINT_MAX; /* human readable text of the record */ -static char *log_text(const struct log *msg) +static char *log_text(const struct printk_log *msg) { - return (char *)msg + sizeof(struct log); + return (char *)msg + sizeof(struct printk_log); } /* optional key/value pair dictionary attached to the record */ -static char *log_dict(const struct log *msg) +static char *log_dict(const struct printk_log *msg) { - return (char *)msg + sizeof(struct log) + msg->text_len; + return (char *)msg + sizeof(struct printk_log) + msg->text_len; } /* get record by index; idx must point to valid msg */ -static struct log *log_from_idx(u32 idx) +static struct printk_log *log_from_idx(u32 idx) { - struct log *msg = (struct log *)(log_buf + idx); + struct printk_log *msg = (struct printk_log *)(log_buf + idx); /* * A length == 0 record is the end of buffer marker. Wrap around and * read the message at the start of the buffer. */ if (!msg->len) - return (struct log *)log_buf; + return (struct printk_log *)log_buf; return msg; } /* get next record; idx must point to valid msg */ static u32 log_next(u32 idx) { - struct log *msg = (struct log *)(log_buf + idx); + struct printk_log *msg = (struct printk_log *)(log_buf + idx); /* length == 0 indicates the end of the buffer; wrap */ /* @@ -291,7 +291,7 @@ static u32 log_next(u32 idx) * return the one after that. */ if (!msg->len) { - msg = (struct log *)log_buf; + msg = (struct printk_log *)log_buf; return msg->len; } return idx + msg->len; @@ -303,11 +303,11 @@ static void log_store(int facility, int level, const char *dict, u16 dict_len, const char *text, u16 text_len) { - struct log *msg; + struct printk_log *msg; u32 size, pad_len; /* number of '\0' padding bytes to next message */ - size = sizeof(struct log) + text_len + dict_len; + size = sizeof(struct printk_log) + text_len + dict_len; pad_len = (-size) & (LOG_ALIGN - 1); size += pad_len; @@ -319,7 +319,7 @@ static void log_store(int facility, int level, else free = log_first_idx - log_next_idx; - if (free > size + sizeof(struct log)) + if (free > size + sizeof(struct printk_log)) break; /* drop old messages until we have enough contiuous space */ @@ -327,18 +327,18 @@ static void log_store(int facility, int level, log_first_seq++; } - if (log_next_idx + size + sizeof(struct log) >= log_buf_len) { + if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) { /* * This message + an additional empty header does not fit * at the end of the buffer. Add an empty header with len == 0 * to signify a wrap around. */ - memset(log_buf + log_next_idx, 0, sizeof(struct log)); + memset(log_buf + log_next_idx, 0, sizeof(struct printk_log)); log_next_idx = 0; } /* fill message */ - msg = (struct log *)(log_buf + log_next_idx); + msg = (struct printk_log *)(log_buf + log_next_idx); memcpy(log_text(msg), text, text_len); msg->text_len = text_len; memcpy(log_dict(msg), dict, dict_len); @@ -351,7 +351,7 @@ static void log_store(int facility, int level, else msg->ts_nsec = local_clock(); memset(log_dict(msg) + dict_len, 0, pad_len); - msg->len = sizeof(struct log) + text_len + dict_len + pad_len; + msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len; /* insert message */ log_next_idx += msg->len; @@ -474,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct devkmsg_user *user = file->private_data; - struct log *msg; + struct printk_log *msg; u64 ts_usec; size_t i; char cont = '-'; @@ -719,14 +719,14 @@ void log_buf_kexec_setup(void) VMCOREINFO_SYMBOL(log_first_idx); VMCOREINFO_SYMBOL(log_next_idx); /* - * Export struct log size and field offsets. User space tools can + * Export struct printk_log size and field offsets. User space tools can * parse it and detect any changes to structure down the line. */ - VMCOREINFO_STRUCT_SIZE(log); - VMCOREINFO_OFFSET(log, ts_nsec); - VMCOREINFO_OFFSET(log, len); - VMCOREINFO_OFFSET(log, text_len); - VMCOREINFO_OFFSET(log, dict_len); + VMCOREINFO_STRUCT_SIZE(printk_log); + VMCOREINFO_OFFSET(printk_log, ts_nsec); + VMCOREINFO_OFFSET(printk_log, len); + VMCOREINFO_OFFSET(printk_log, text_len); + VMCOREINFO_OFFSET(printk_log, dict_len); } #endif @@ -879,7 +879,7 @@ static size_t print_time(u64 ts, char *buf) (unsigned long)ts, rem_nsec / 1000); } -static size_t print_prefix(const struct log *msg, bool syslog, char *buf) +static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf) { size_t len = 0; unsigned int prefix = (msg->facility << 3) | msg->level; @@ -902,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf) return len; } -static size_t msg_print_text(const struct log *msg, enum log_flags prev, +static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev, bool syslog, char *buf, size_t size) { const char *text = log_text(msg); @@ -964,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev, static int syslog_print(char __user *buf, int size) { char *text; - struct log *msg; + struct printk_log *msg; int len = 0; text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); @@ -1055,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) idx = clear_idx; prev = 0; while (seq < log_next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); len += msg_print_text(msg, prev, true, NULL, 0); prev = msg->flags; @@ -1068,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) idx = clear_idx; prev = 0; while (len > size && seq < log_next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); len -= msg_print_text(msg, prev, true, NULL, 0); prev = msg->flags; @@ -1082,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) len = 0; prev = 0; while (len >= 0 && seq < next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); int textlen; textlen = msg_print_text(msg, prev, true, text, @@ -1228,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) error = 0; while (seq < log_next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); error += msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); @@ -1714,10 +1714,10 @@ static struct cont { u8 level; bool flushed:1; } cont; -static struct log *log_from_idx(u32 idx) { return NULL; } +static struct printk_log *log_from_idx(u32 idx) { return NULL; } static u32 log_next(u32 idx) { return 0; } static void call_console_drivers(int level, const char *text, size_t len) {} -static size_t msg_print_text(const struct log *msg, enum log_flags prev, +static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev, bool syslog, char *buf, size_t size) { return 0; } static size_t cont_print_text(char *text, size_t size) { return 0; } @@ -2029,7 +2029,7 @@ void console_unlock(void) console_cont_flush(text, sizeof(text)); again: for (;;) { - struct log *msg; + struct printk_log *msg; size_t len; int level; @@ -2645,7 +2645,7 @@ void kmsg_dump(enum kmsg_dump_reason reason) bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, char *line, size_t size, size_t *len) { - struct log *msg; + struct printk_log *msg; size_t l = 0; bool ret = false; @@ -2757,7 +2757,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, idx = dumper->cur_idx; prev = 0; while (seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); l += msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); @@ -2770,7 +2770,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, idx = dumper->cur_idx; prev = 0; while (l > size && seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); l -= msg_print_text(msg, prev, true, NULL, 0); idx = log_next(idx); @@ -2785,7 +2785,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, l = 0; prev = 0; while (seq < dumper->next_seq) { - struct log *msg = log_from_idx(idx); + struct printk_log *msg = log_from_idx(idx); l += msg_print_text(msg, prev, syslog, buf + l, size - l); idx = log_next(idx); -- cgit v0.10.2 From 22f2020f84c6da2dd0acb2dce12e39e59ff7c8be Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Wed, 31 Jul 2013 13:53:48 -0700 Subject: vmpressure: change vmpressure::sr_lock to spinlock There is nothing that can sleep inside critical sections protected by this lock and those sections are really small so there doesn't make much sense to use mutex for them. Change the log to a spinlock Signed-off-by: Michal Hocko Reported-by: Tejun Heo Cc: Anton Vorontsov Cc: Johannes Weiner Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: Li Zefan Reviewed-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h index 76be077..2081680 100644 --- a/include/linux/vmpressure.h +++ b/include/linux/vmpressure.h @@ -12,7 +12,7 @@ struct vmpressure { unsigned long scanned; unsigned long reclaimed; /* The lock is used to keep the scanned/reclaimed above in sync. */ - struct mutex sr_lock; + struct spinlock sr_lock; /* The list of vmpressure_event structs. */ struct list_head events; diff --git a/mm/vmpressure.c b/mm/vmpressure.c index 736a601..f4ee6a1 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -180,12 +180,12 @@ static void vmpressure_work_fn(struct work_struct *work) if (!vmpr->scanned) return; - mutex_lock(&vmpr->sr_lock); + spin_lock(&vmpr->sr_lock); scanned = vmpr->scanned; reclaimed = vmpr->reclaimed; vmpr->scanned = 0; vmpr->reclaimed = 0; - mutex_unlock(&vmpr->sr_lock); + spin_unlock(&vmpr->sr_lock); do { if (vmpressure_event(vmpr, scanned, reclaimed)) @@ -240,11 +240,11 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, if (!scanned) return; - mutex_lock(&vmpr->sr_lock); + spin_lock(&vmpr->sr_lock); vmpr->scanned += scanned; vmpr->reclaimed += reclaimed; scanned = vmpr->scanned; - mutex_unlock(&vmpr->sr_lock); + spin_unlock(&vmpr->sr_lock); if (scanned < vmpressure_win || work_pending(&vmpr->work)) return; @@ -367,7 +367,7 @@ void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft, */ void vmpressure_init(struct vmpressure *vmpr) { - mutex_init(&vmpr->sr_lock); + spin_lock_init(&vmpr->sr_lock); mutex_init(&vmpr->events_lock); INIT_LIST_HEAD(&vmpr->events); INIT_WORK(&vmpr->work, vmpressure_work_fn); -- cgit v0.10.2 From 8e0ed445b3478468372449859c45c6b3032acf2f Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Wed, 31 Jul 2013 13:53:50 -0700 Subject: vmpressure: do not check for pending work to prevent from new work because it is racy and it doesn't give us much anyway as schedule_work handles this case already. Signed-off-by: Michal Hocko Reported-by: Tejun Heo Cc: Anton Vorontsov Cc: Johannes Weiner Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: Li Zefan Acked-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmpressure.c b/mm/vmpressure.c index f4ee6a1..192f973 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -246,7 +246,7 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, scanned = vmpr->scanned; spin_unlock(&vmpr->sr_lock); - if (scanned < vmpressure_win || work_pending(&vmpr->work)) + if (scanned < vmpressure_win) return; schedule_work(&vmpr->work); } -- cgit v0.10.2 From 33cb876e947b9ddda8dca3fb99234b743a597ef9 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Wed, 31 Jul 2013 13:53:51 -0700 Subject: vmpressure: make sure there are no events queued after memcg is offlined vmpressure is called synchronously from reclaim where the target_memcg is guaranteed to be alive but the eventfd is signaled from the work queue context. This means that memcg (along with vmpressure structure which is embedded into it) might go away while the work item is pending which would result in use-after-release bug. We have two possible ways how to fix this. Either vmpressure pins memcg before it schedules vmpr->work and unpin it in vmpressure_work_fn or explicitely flush the work item from the css_offline context (as suggested by Tejun). This patch implements the later one and it introduces vmpressure_cleanup which flushes the vmpressure work queue item item. It hooks into mem_cgroup_css_offline after the memcg itself is cleaned up. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Michal Hocko Reported-by: Tejun Heo Cc: Anton Vorontsov Cc: Johannes Weiner Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: Li Zefan Acked-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h index 2081680..7dc17e2 100644 --- a/include/linux/vmpressure.h +++ b/include/linux/vmpressure.h @@ -30,6 +30,7 @@ extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio); extern void vmpressure_init(struct vmpressure *vmpr); +extern void vmpressure_cleanup(struct vmpressure *vmpr); extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg); extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr); extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 00a7a66..c290a1c 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6335,6 +6335,7 @@ static void mem_cgroup_css_offline(struct cgroup *cont) mem_cgroup_invalidate_reclaim_iterators(memcg); mem_cgroup_reparent_charges(memcg); mem_cgroup_destroy_all_caches(memcg); + vmpressure_cleanup(&memcg->vmpressure); } static void mem_cgroup_css_free(struct cgroup *cont) diff --git a/mm/vmpressure.c b/mm/vmpressure.c index 192f973..0c1e37d 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -372,3 +372,19 @@ void vmpressure_init(struct vmpressure *vmpr) INIT_LIST_HEAD(&vmpr->events); INIT_WORK(&vmpr->work, vmpressure_work_fn); } + +/** + * vmpressure_cleanup() - shuts down vmpressure control structure + * @vmpr: Structure to be cleaned up + * + * This function should be called before the structure in which it is + * embedded is cleaned up. + */ +void vmpressure_cleanup(struct vmpressure *vmpr) +{ + /* + * Make sure there is no pending work before eventfd infrastructure + * goes away. + */ + flush_work(&vmpr->work); +} -- cgit v0.10.2 From 50861f5a02dbf939c27d35a26c472885e2844188 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 23 Jul 2013 12:27:52 -0400 Subject: parisc: Fix cache routines to ignore vma's with an invalid pfn The parisc architecture does not have a pte special bit. As a result, special mappings are handled with the VM_PFNMAP and VM_MIXEDMAP flags. VM_MIXEDMAP mappings may or may not have a "struct page" backing. When pfn_valid() is false, there is no "struct page" backing. Otherwise, they are treated as normal pages. The FireGL driver uses the VM_MIXEDMAP without a backing "struct page". This treatment caused a panic due to a TLB data miss in update_mmu_cache. This appeared to be in the code generated for page_address(). We were in fact using a very circular bit of code to determine the physical address of the PFN in various cache routines. This wasn't valid when there was no "struct page" backing. The needed address can in fact be determined simply from the PFN itself without using the "struct page". The attached patch updates update_mmu_cache(), flush_cache_mm(), flush_cache_range() and flush_cache_page() to check pfn_valid() and to directly compute the PFN physical and virtual addresses. Signed-off-by: John David Anglin Cc: # 3.10 Signed-off-by: Helge Deller diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 2e65aa5..c035673 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -71,18 +71,27 @@ flush_cache_all_local(void) } EXPORT_SYMBOL(flush_cache_all_local); +/* Virtual address of pfn. */ +#define pfn_va(pfn) __va(PFN_PHYS(pfn)) + void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { - struct page *page = pte_page(*ptep); + unsigned long pfn = pte_pfn(*ptep); + struct page *page; - if (pfn_valid(page_to_pfn(page)) && page_mapping(page) && - test_bit(PG_dcache_dirty, &page->flags)) { + /* We don't have pte special. As a result, we can be called with + an invalid pfn and we don't need to flush the kernel dcache page. + This occurs with FireGL card in C8000. */ + if (!pfn_valid(pfn)) + return; - flush_kernel_dcache_page(page); + page = pfn_to_page(pfn); + if (page_mapping(page) && test_bit(PG_dcache_dirty, &page->flags)) { + flush_kernel_dcache_page_addr(pfn_va(pfn)); clear_bit(PG_dcache_dirty, &page->flags); } else if (parisc_requires_coherency()) - flush_kernel_dcache_page(page); + flush_kernel_dcache_page_addr(pfn_va(pfn)); } void @@ -495,44 +504,42 @@ static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr) void flush_cache_mm(struct mm_struct *mm) { + struct vm_area_struct *vma; + pgd_t *pgd; + /* Flushing the whole cache on each cpu takes forever on rp3440, etc. So, avoid it if the mm isn't too big. */ - if (mm_total_size(mm) < parisc_cache_flush_threshold) { - struct vm_area_struct *vma; - - if (mm->context == mfsp(3)) { - for (vma = mm->mmap; vma; vma = vma->vm_next) { - flush_user_dcache_range_asm(vma->vm_start, - vma->vm_end); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_range_asm( - vma->vm_start, vma->vm_end); - } - } else { - pgd_t *pgd = mm->pgd; - - for (vma = mm->mmap; vma; vma = vma->vm_next) { - unsigned long addr; - - for (addr = vma->vm_start; addr < vma->vm_end; - addr += PAGE_SIZE) { - pte_t *ptep = get_ptep(pgd, addr); - if (ptep != NULL) { - pte_t pte = *ptep; - __flush_cache_page(vma, addr, - page_to_phys(pte_page(pte))); - } - } - } + if (mm_total_size(mm) >= parisc_cache_flush_threshold) { + flush_cache_all(); + return; + } + + if (mm->context == mfsp(3)) { + for (vma = mm->mmap; vma; vma = vma->vm_next) { + flush_user_dcache_range_asm(vma->vm_start, vma->vm_end); + if ((vma->vm_flags & VM_EXEC) == 0) + continue; + flush_user_icache_range_asm(vma->vm_start, vma->vm_end); } return; } -#ifdef CONFIG_SMP - flush_cache_all(); -#else - flush_cache_all_local(); -#endif + pgd = mm->pgd; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long addr; + + for (addr = vma->vm_start; addr < vma->vm_end; + addr += PAGE_SIZE) { + unsigned long pfn; + pte_t *ptep = get_ptep(pgd, addr); + if (!ptep) + continue; + pfn = pte_pfn(*ptep); + if (!pfn_valid(pfn)) + continue; + __flush_cache_page(vma, addr, PFN_PHYS(pfn)); + } + } } void @@ -556,33 +563,32 @@ flush_user_icache_range(unsigned long start, unsigned long end) void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { + unsigned long addr; + pgd_t *pgd; + BUG_ON(!vma->vm_mm->context); - if ((end - start) < parisc_cache_flush_threshold) { - if (vma->vm_mm->context == mfsp(3)) { - flush_user_dcache_range_asm(start, end); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_range_asm(start, end); - } else { - unsigned long addr; - pgd_t *pgd = vma->vm_mm->pgd; - - for (addr = start & PAGE_MASK; addr < end; - addr += PAGE_SIZE) { - pte_t *ptep = get_ptep(pgd, addr); - if (ptep != NULL) { - pte_t pte = *ptep; - flush_cache_page(vma, - addr, pte_pfn(pte)); - } - } - } - } else { -#ifdef CONFIG_SMP + if ((end - start) >= parisc_cache_flush_threshold) { flush_cache_all(); -#else - flush_cache_all_local(); -#endif + return; + } + + if (vma->vm_mm->context == mfsp(3)) { + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); + return; + } + + pgd = vma->vm_mm->pgd; + for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) { + unsigned long pfn; + pte_t *ptep = get_ptep(pgd, addr); + if (!ptep) + continue; + pfn = pte_pfn(*ptep); + if (pfn_valid(pfn)) + __flush_cache_page(vma, addr, PFN_PHYS(pfn)); } } @@ -591,9 +597,10 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long { BUG_ON(!vma->vm_mm->context); - flush_tlb_page(vma, vmaddr); - __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); - + if (pfn_valid(pfn)) { + flush_tlb_page(vma, vmaddr); + __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); + } } #ifdef CONFIG_PARISC_TMPALIAS -- cgit v0.10.2 From 06f0cce43a32bd2357cea1d8733bba48693d556b Mon Sep 17 00:00:00 2001 From: Alex Ivanov Date: Wed, 10 Jul 2013 21:14:55 +0200 Subject: parisc: agp/parisc-agp: allow binding of user memory to the AGP GART MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow binding of user memory to the AGP GART on systems with HP Quicksilver AGP bus. This resolves 'bind memory failed' error seen in dmesg: [29.365973] [TTM] AGP Bind memory failed. … [29.367030] [drm] Forcing AGP to PCI mode The system doesn't more fail to bind the memory, and hence not falling back to the PCI mode (if other failures aren't detected). This is just a simple write down from the following patches: agp/amd-k7: Allow binding user memory to the AGP GART agp/hp-agp: Allow binding user memory to the AGP GART Signed-off-by: Alex Ivanov Cc: # 3.10 Signed-off-by: Helge Deller diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index bf5d247..15f2e70 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -129,7 +129,8 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) off_t j, io_pg_start; int io_pg_count; - if (type != 0 || mem->type != 0) { + if (type != mem->type || + agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) { return -EINVAL; } @@ -175,7 +176,8 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) struct _parisc_agp_info *info = &parisc_agp_info; int i, io_pg_start, io_pg_count; - if (type != 0 || mem->type != 0) { + if (type != mem->type || + agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) { return -EINVAL; } -- cgit v0.10.2 From 78f1386cb0777e7413df734ddc30e41d0a6522a9 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 10 Jul 2013 23:50:35 +0200 Subject: parisc: add defconfig for c8000 machine Signed-off-by: Helge Deller diff --git a/arch/parisc/configs/c8000_defconfig b/arch/parisc/configs/c8000_defconfig new file mode 100644 index 0000000..f110063 --- /dev/null +++ b/arch/parisc/configs/c8000_defconfig @@ -0,0 +1,279 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_FHANDLE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_LZO=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_PA8X00=y +CONFIG_MLONGCALLS=y +CONFIG_64BIT=y +CONFIG_SMP=y +CONFIG_PREEMPT=y +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_IOMMU_CCIO=y +CONFIG_PCI=y +CONFIG_PCI_LBA=y +# CONFIG_SUPERIO is not set +# CONFIG_CHASSIS_LCD_LED is not set +# CONFIG_PDC_CHASSIS is not set +# CONFIG_PDC_CHASSIS_WARN is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=m +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_BEET=m +CONFIG_INET_DIAG=m +# CONFIG_IPV6 is not set +CONFIG_IP_DCCP=m +# CONFIG_IP_DCCP_CCID3 is not set +CONFIG_TIPC=m +CONFIG_LLC2=m +CONFIG_DNS_RESOLVER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_STANDALONE is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +CONFIG_BLK_DEV_UMEM=m +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +CONFIG_BLK_DEV_SX8=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=6144 +CONFIG_CDROM_PKTCDVD=m +CONFIG_CDROM_PKTCDVD_WCACHE=y +CONFIG_ATA_OVER_ETH=m +CONFIG_IDE=y +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_PLATFORM=y +CONFIG_BLK_DEV_GENERIC=y +CONFIG_BLK_DEV_SIIMAGE=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=m +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_ISCSI_TCP=m +CONFIG_ISCSI_BOOT_SYSFS=m +CONFIG_FUSION=y +CONFIG_FUSION_SPI=y +CONFIG_FUSION_SAS=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_NETCONSOLE=m +CONFIG_TUN=y +CONFIG_E1000=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_MPPE=m +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_WLAN is not set +CONFIG_INPUT_FF_MEMLESS=m +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_HIL_OLD is not set +# CONFIG_KEYBOARD_HIL is not set +CONFIG_MOUSE_PS2=m +CONFIG_INPUT_MISC=y +CONFIG_INPUT_CM109=m +CONFIG_SERIO_SERPORT=m +CONFIG_SERIO_PARKBD=m +CONFIG_SERIO_GSCPS2=m +# CONFIG_HP_SDC is not set +CONFIG_SERIO_PCIPS2=m +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_RAW=m +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=8 +CONFIG_SERIAL_8250_RUNTIME_UARTS=8 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_MUX is not set +CONFIG_SERIAL_JSM=m +CONFIG_PRINTER=y +CONFIG_HW_RANDOM=y +CONFIG_RAW_DRIVER=m +CONFIG_PTP_1588_CLOCK=y +CONFIG_SSB=m +CONFIG_SSB_DRIVER_PCICORE=y +CONFIG_AGP=y +CONFIG_AGP_PARISC=y +CONFIG_DRM=y +CONFIG_DRM_RADEON=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_FOREIGN_ENDIAN=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_TILEBLITTING=y +# CONFIG_FB_STI is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_STI_CONSOLE is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +CONFIG_SOUND=m +CONFIG_SND=m +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQ_DUMMY=m +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_AD1889=m +# CONFIG_SND_USB is not set +# CONFIG_SND_GSC is not set +CONFIG_HID_A4TECH=m +CONFIG_HID_APPLE=m +CONFIG_HID_BELKIN=m +CONFIG_HID_CHERRY=m +CONFIG_HID_CHICONY=m +CONFIG_HID_CYPRESS=m +CONFIG_HID_DRAGONRISE=m +CONFIG_HID_EZKEY=m +CONFIG_HID_KYE=m +CONFIG_HID_GYRATION=m +CONFIG_HID_TWINHAN=m +CONFIG_HID_KENSINGTON=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MONTEREY=m +CONFIG_HID_NTRIG=m +CONFIG_HID_ORTEK=m +CONFIG_HID_PANTHERLORD=m +CONFIG_HID_PETALYNX=m +CONFIG_HID_SAMSUNG=m +CONFIG_HID_SUNPLUS=m +CONFIG_HID_GREENASIA=m +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_HID_TOPSEED=m +CONFIG_HID_THRUSTMASTER=m +CONFIG_HID_ZEROPLUS=m +CONFIG_USB_HID=m +CONFIG_USB=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_EXT4_FS=m +CONFIG_REISERFS_FS=m +CONFIG_REISERFS_PROC_INFO=y +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_QUOTA=y +CONFIG_QFMT_V1=m +CONFIG_QFMT_V2=m +CONFIG_AUTOFS4_FS=m +CONFIG_FUSE_FS=m +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_XATTR=y +CONFIG_NFS_FS=m +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m +CONFIG_UNUSED_SYMBOLS=y +CONFIG_DEBUG_FS=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SLAB_LEAK=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_PANIC_ON_OOPS=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_RT_MUTEX_TESTER=y +CONFIG_PROVE_RCU_DELAY=y +CONFIG_DEBUG_BLOCK_EXT_DEVT=y +CONFIG_LATENCYTOP=y +CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y +CONFIG_KEYS=y +# CONFIG_CRYPTO_HW is not set +CONFIG_FONTS=y -- cgit v0.10.2 From 5a0ce2dc218ea9a6e659dcc5a4827975cb13104f Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 28 Jul 2013 17:49:53 -0400 Subject: parisc: Remove arch/parisc/kernel/sys32.h header The KERNEL_SYSCALL define is not used anymore so the header can be removed. Signed-off-by: John David Anglin Signed-off-by: Helge Deller diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 940188d..07349b0 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -56,13 +56,6 @@ #define A(__x) ((unsigned long)(__x)) /* - * Atomically swap in the new signal mask, and wait for a signal. - */ -#ifdef CONFIG_64BIT -#include "sys32.h" -#endif - -/* * Do a signal return - restore sigcontext. */ diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index 33eca1b..6c6a271 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -34,7 +34,6 @@ #include #include "signal32.h" -#include "sys32.h" #define DEBUG_COMPAT_SIG 0 #define DEBUG_COMPAT_SIG_LEVEL 2 diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h deleted file mode 100644 index 60dd470..0000000 --- a/arch/parisc/kernel/sys32.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2002 Richard Hirst - * Copyright (C) 2003 James Bottomley - * Copyright (C) 2003 Randolph Chung - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _PARISC64_KERNEL_SYS32_H -#define _PARISC64_KERNEL_SYS32_H - -#include - -/* Call a kernel syscall which will use kernel space instead of user - * space for its copy_to/from_user. - */ -#define KERNEL_SYSCALL(ret, syscall, args...) \ -{ \ - mm_segment_t old_fs = get_fs(); \ - set_fs(KERNEL_DS); \ - ret = syscall(args); \ - set_fs (old_fs); \ -} - -#endif diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index a134ff4..bb9f3b6 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c @@ -42,8 +42,6 @@ #include #include -#include "sys32.h" - #undef DEBUG #ifdef DEBUG -- cgit v0.10.2 From dd5e6d6a3db09b16b7c222943977865eead88cc3 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Tue, 30 Jul 2013 02:02:16 +0200 Subject: parisc: Fix interrupt routing for C8000 serial ports We can't use dev->mod_index for selecting the interrupt routing entry, because it's not an index into interrupt routing table. It will be even wrong on a machine with 2 CPUs (4 cores). But all needed information is contained in the PAT entries for the serial ports. mod[0] contains the iosapic address and mod_info has some indications for the interrupt input (at least it looks like it). This patch implements the searching for the right iosapic and uses this interrupt input information. Signed-off-by: Thomas Bogendoerfer Cc: # 3.10 Signed-off-by: Helge Deller diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h index 9afdad6..eaf4dc1 100644 --- a/arch/parisc/include/asm/parisc-device.h +++ b/arch/parisc/include/asm/parisc-device.h @@ -23,6 +23,7 @@ struct parisc_device { /* generic info returned from pdc_pat_cell_module() */ unsigned long mod_info; /* PAT specific - Misc Module info */ unsigned long pmod_loc; /* physical Module location */ + unsigned long mod0; #endif u64 dma_mask; /* DMA mask for I/O */ struct device dev; @@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d) extern struct bus_type parisc_bus_type; +int iosapic_serial_irq(struct parisc_device *dev); + #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index 3295ef4..f0b6722 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c @@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index) /* REVISIT: who is the consumer of this? not sure yet... */ dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */ dev->pmod_loc = pa_pdc_cell->mod_location; + dev->mod0 = pa_pdc_cell->mod[0]; register_parisc_device(dev); /* advertise device */ diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index e79e006..9ee04b4 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) return pcidev->irq; } -static struct iosapic_info *first_isi = NULL; +static struct iosapic_info *iosapic_list; #ifdef CONFIG_64BIT -int iosapic_serial_irq(int num) +int iosapic_serial_irq(struct parisc_device *dev) { - struct iosapic_info *isi = first_isi; - struct irt_entry *irte = NULL; /* only used if PAT PDC */ + struct iosapic_info *isi; + struct irt_entry *irte; struct vector_info *vi; - int isi_line; /* line used by device */ + int cnt; + int intin; + + intin = (dev->mod_info >> 24) & 15; /* lookup IRT entry for isi/slot/pin set */ - irte = &irt_cell[num]; + for (cnt = 0; cnt < irt_num_entry; cnt++) { + irte = &irt_cell[cnt]; + if (COMPARE_IRTE_ADDR(irte, dev->mod0) && + irte->dest_iosapic_intin == intin) + break; + } + if (cnt >= irt_num_entry) + return 0; /* no irq found, force polling */ DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", irte, @@ -834,11 +844,17 @@ int iosapic_serial_irq(int num) irte->src_seg_id, irte->dest_iosapic_intin, (u32) irte->dest_iosapic_addr); - isi_line = irte->dest_iosapic_intin; + + /* search for iosapic */ + for (isi = iosapic_list; isi; isi = isi->isi_next) + if (isi->isi_hpa == dev->mod0) + break; + if (!isi) + return 0; /* no iosapic found, force polling */ /* get vector info for this input line */ - vi = isi->isi_vector + isi_line; - DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi); + vi = isi->isi_vector + intin; + DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi); /* If this IRQ line has already been setup, skip it */ if (vi->irte) @@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa) vip->irqline = (unsigned char) cnt; vip->iosapic = isi; } - if (!first_isi) - first_isi = isi; + isi->isi_next = iosapic_list; + iosapic_list = isi; return isi; } diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index bb91b47..2e3ea1a 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev) int err; #ifdef CONFIG_64BIT - extern int iosapic_serial_irq(int cellnum); if (!dev->irq && (dev->id.sversion == 0xad)) - dev->irq = iosapic_serial_irq(dev->mod_index-1); + dev->irq = iosapic_serial_irq(dev); #endif if (!dev->irq) { -- cgit v0.10.2 From b2f47377e871a5f3cc5bd0dd58d3ea1fbc58948d Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 31 Jul 2013 17:21:22 +0800 Subject: net/usb/r815x: replace USB buffer from stack to DMA-able Some USB buffers use stack which may not be DMA-able. Use the buffers from kmalloc to replace those one. Signed-off-by: Hayes Wang Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index 8523922..e9b99ba 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -24,34 +24,43 @@ static int pla_read_word(struct usb_device *udev, u16 index) { - int data, ret; + int ret; u8 shift = index & 2; - __le32 ocp_data; + __le32 *tmp; + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; index &= ~3; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), RTL815x_REQ_GET_REGS, RTL815x_REQT_READ, - index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data), - 500); + index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); if (ret < 0) - return ret; + goto out2; - data = __le32_to_cpu(ocp_data); - data >>= (shift * 8); - data &= 0xffff; + ret = __le32_to_cpu(*tmp); + ret >>= (shift * 8); + ret &= 0xffff; - return data; +out2: + kfree(tmp); + return ret; } static int pla_write_word(struct usb_device *udev, u16 index, u32 data) { - __le32 ocp_data; + __le32 *tmp; u32 mask = 0xffff; u16 byen = BYTE_EN_WORD; u8 shift = index & 2; int ret; + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + data &= mask; if (shift) { @@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data) ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), RTL815x_REQ_GET_REGS, RTL815x_REQT_READ, - index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data), - 500); + index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); if (ret < 0) - return ret; + goto out3; - data |= __le32_to_cpu(ocp_data) & ~mask; - ocp_data = __cpu_to_le32(data); + data |= __le32_to_cpu(*tmp) & ~mask; + *tmp = __cpu_to_le32(data); ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE, - index, MCU_TYPE_PLA | byen, &ocp_data, - sizeof(ocp_data), 500); + index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp), + 500); +out3: + kfree(tmp); return ret; } -- cgit v0.10.2 From b771721a748875e3654debdf68ad4708477f18c4 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 31 Jul 2013 17:21:23 +0800 Subject: net/usb/r815x: avoid to call mdio functions for runtime-suspended device Don't replace the usb_control_msg() with usbnet_{read,write}_cmd() which couldn't be called inside suspend/resume callback. Keep the basic functions unlimited. Instead, using usb_autopm_get_interface() and usb_autopm_put_interface() in r815x_mdio_{read,write}(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index e9b99ba..1a80e76 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -126,11 +126,18 @@ out1: static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg) { struct usbnet *dev = netdev_priv(netdev); + int ret; if (phy_id != R815x_PHY_ID) return -EINVAL; - return ocp_reg_read(dev, BASE_MII + reg * 2); + if (usb_autopm_get_interface(dev->intf) < 0) + return -ENODEV; + + ret = ocp_reg_read(dev, BASE_MII + reg * 2); + + usb_autopm_put_interface(dev->intf); + return ret; } static @@ -141,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val) if (phy_id != R815x_PHY_ID) return; + if (usb_autopm_get_interface(dev->intf) < 0) + return; + ocp_reg_write(dev, BASE_MII + reg * 2, val); + + usb_autopm_put_interface(dev->intf); } static int r8153_bind(struct usbnet *dev, struct usb_interface *intf) -- cgit v0.10.2 From 543ae7f9c4e69816043ac3b526310353b413b325 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 31 Jul 2013 17:21:24 +0800 Subject: net/usb/r815x: change the return value for bind functions Replace 0 with the result from usbnet_cdc_bind(). Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index 1a80e76..2df2f4f 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -172,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.phy_id = R815x_PHY_ID; dev->mii.supports_gmii = 1; - return 0; + return status; } static int r8152_bind(struct usbnet *dev, struct usb_interface *intf) @@ -191,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.phy_id = R815x_PHY_ID; dev->mii.supports_gmii = 0; - return 0; + return status; } static const struct driver_info r8152_info = { -- cgit v0.10.2 From 31787f5398c3c5aced755e8abd5ae00a2c371cd4 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 31 Jul 2013 17:21:25 +0800 Subject: net/usb/r8152: make sure the USB buffer is DMA-able Allocate the required memory before calling usb_control_msg. And the additional memory copy is necessary. Signed-off-by: Hayes Wang Acked-by: Greg Kroah-Hartman Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ee13f9e..ef033ab 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32; static int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { - return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), + int ret; + void *tmp; + + tmp = kmalloc(size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, - value, index, data, size, 500); + value, index, tmp, size, 500); + + memcpy(data, tmp, size); + kfree(tmp); + + return ret; } static int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { - return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), + int ret; + void *tmp; + + tmp = kmalloc(size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + memcpy(tmp, data, size); + + ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, - value, index, data, size, 500); + value, index, tmp, size, 500); + + kfree(tmp); + return ret; } static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, @@ -685,21 +709,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) static inline void set_ethernet_addr(struct r8152 *tp) { struct net_device *dev = tp->netdev; - u8 *node_id; + u8 node_id[8] = {0}; - node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL); - if (!node_id) { - netif_err(tp, probe, dev, "out of memory"); - return; - } - - if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0) + if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0) netif_notice(tp, probe, dev, "inet addr fail\n"); else { memcpy(dev->dev_addr, node_id, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); } - kfree(node_id); } static int rtl8152_set_mac_address(struct net_device *netdev, void *p) @@ -882,15 +899,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev) static void _rtl8152_set_rx_mode(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); - u32 tmp, *mc_filter; /* Multicast hash filter */ + u32 mc_filter[2]; /* Multicast hash filter */ + __le32 tmp[2]; u32 ocp_data; - mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL); - if (!mc_filter) { - netif_err(tp, link, netdev, "out of memory"); - return; - } - clear_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_stop_queue(netdev); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -918,14 +930,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev) } } - tmp = mc_filter[0]; - mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1])); - mc_filter[1] = __cpu_to_le32(swab32(tmp)); + tmp[0] = __cpu_to_le32(swab32(mc_filter[1])); + tmp[1] = __cpu_to_le32(swab32(mc_filter[0])); - pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter); + pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); netif_wake_queue(netdev); - kfree(mc_filter); } static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, -- cgit v0.10.2 From c8826de8af3b3c849ba9197851211ced62387a57 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 31 Jul 2013 17:21:26 +0800 Subject: net/usb/r8152: adjust relative ocp function - fix the conversion between cpu and __le32 - replace some pla_ocp and usb_ocp functions with generic_ocp function Signed-off-by: Hayes Wang Signed-off-by: David S. Miller diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ef033ab..11c51f2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -514,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data) static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index) { - u32 data; + __le32 data; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(data), &data, type); return __le32_to_cpu(data); } static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data) { - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data); - else - usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data); + __le32 tmp = __cpu_to_le32(data); + + generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type); } static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) { u32 data; + __le32 tmp; u8 shift = index & 2; index &= ~3; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - data = __le32_to_cpu(data); + data = __le32_to_cpu(tmp); data >>= (shift * 8); data &= 0xffff; @@ -553,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index) static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) { - u32 tmp, mask = 0xffff; + u32 mask = 0xffff; + __le32 tmp; u16 byen = BYTE_EN_WORD; u8 shift = index & 2; @@ -566,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(tmp), &tmp); - else - usb_ocp_read(tp, index, sizeof(tmp), &tmp); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - tmp = __le32_to_cpu(tmp) & ~mask; - tmp |= data; - tmp = __cpu_to_le32(tmp); + data |= __le32_to_cpu(tmp) & ~mask; + tmp = __cpu_to_le32(data); - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp); - else - usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp); + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); } static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) { u32 data; + __le32 tmp; u8 shift = index & 3; index &= ~3; - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(data), &data); - else - usb_ocp_read(tp, index, sizeof(data), &data); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - data = __le32_to_cpu(data); + data = __le32_to_cpu(tmp); data >>= (shift * 8); data &= 0xff; @@ -602,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index) static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) { - u32 tmp, mask = 0xff; + u32 mask = 0xff; + __le32 tmp; u16 byen = BYTE_EN_BYTE; u8 shift = index & 3; @@ -615,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) index &= ~3; } - if (type == MCU_TYPE_PLA) - pla_ocp_read(tp, index, sizeof(tmp), &tmp); - else - usb_ocp_read(tp, index, sizeof(tmp), &tmp); + generic_ocp_read(tp, index, sizeof(tmp), &tmp, type); - tmp = __le32_to_cpu(tmp) & ~mask; - tmp |= data; - tmp = __cpu_to_le32(tmp); + data |= __le32_to_cpu(tmp) & ~mask; + tmp = __cpu_to_le32(data); - if (type == MCU_TYPE_PLA) - pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp); - else - usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp); + generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); } static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) -- cgit v0.10.2 From 8cb3b9c3642c0263d48f31d525bcee7170eedc20 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 30 Jul 2013 13:23:39 +0300 Subject: net_sched: info leak in atm_tc_dump_class() The "pvc" struct has a hole after pvc.sap_family which is not cleared. Signed-off-by: Dan Carpenter Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index ca8e0a5..1f9c314 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -605,6 +605,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, struct sockaddr_atmpvc pvc; int state; + memset(&pvc, 0, sizeof(pvc)); pvc.sap_family = AF_ATMPVC; pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1; pvc.sap_addr.vpi = flow->vcc->vpi; -- cgit v0.10.2 From d9d10a30964504af834d8d250a0c76d4ae91eb1e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 30 Jul 2013 10:31:00 -0700 Subject: ndisc: Add missing inline to ndisc_addr_option_pad Signed-off-by: Joe Perches Signed-off-by: David S. Miller diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 949d775..6fea323 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -119,7 +119,7 @@ extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may * also need a pad of 2. */ -static int ndisc_addr_option_pad(unsigned short type) +static inline int ndisc_addr_option_pad(unsigned short type) { switch (type) { case ARPHRD_INFINIBAND: return 2; -- cgit v0.10.2 From cf3c4c03060b688cbc389ebc5065ebcce5653e96 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 31 Jul 2013 09:03:56 -0400 Subject: 8139cp: Add dma_mapping_error checking Self explanitory dma_mapping_error addition to the 8139 driver, based on this: https://bugzilla.redhat.com/show_bug.cgi?id=947250 It showed several backtraces arising for dma_map_* usage without checking the return code on the mapping. Add the check and abort the rx/tx operation if its failed. Untested as I have no hardware and the reporter has wandered off, but seems pretty straightforward. Signed-off-by: Neil Horman CC: "David S. Miller" CC: Francois Romieu Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index e6acb9f..6f35f84 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -478,7 +478,7 @@ rx_status_loop: while (1) { u32 status, len; - dma_addr_t mapping; + dma_addr_t mapping, new_mapping; struct sk_buff *skb, *new_skb; struct cp_desc *desc; const unsigned buflen = cp->rx_buf_sz; @@ -520,6 +520,13 @@ rx_status_loop: goto rx_next; } + new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, + PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&cp->pdev->dev, new_mapping)) { + dev->stats.rx_dropped++; + goto rx_next; + } + dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE); @@ -531,12 +538,11 @@ rx_status_loop: skb_put(skb, len); - mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen, - PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail] = new_skb; cp_rx_skb(cp, skb, desc); rx++; + mapping = new_mapping; rx_next: cp->rx_ring[rx_tail].opts2 = 0; @@ -716,6 +722,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb) TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00; } +static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb, + int first, int entry_last) +{ + int frag, index; + struct cp_desc *txd; + skb_frag_t *this_frag; + for (frag = 0; frag+first < entry_last; frag++) { + index = first+frag; + cp->tx_skb[index] = NULL; + txd = &cp->tx_ring[index]; + this_frag = &skb_shinfo(skb)->frags[frag]; + dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr), + skb_frag_size(this_frag), PCI_DMA_TODEVICE); + } +} + static netdev_tx_t cp_start_xmit (struct sk_buff *skb, struct net_device *dev) { @@ -749,6 +771,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, len = skb->len; mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) + goto out_dma_error; + txd->opts2 = opts2; txd->addr = cpu_to_le64(mapping); wmb(); @@ -786,6 +811,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, first_len = skb_headlen(skb); first_mapping = dma_map_single(&cp->pdev->dev, skb->data, first_len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, first_mapping)) + goto out_dma_error; + cp->tx_skb[entry] = skb; entry = NEXT_TX(entry); @@ -799,6 +827,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, mapping = dma_map_single(&cp->pdev->dev, skb_frag_address(this_frag), len, PCI_DMA_TODEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) { + unwind_tx_frag_mapping(cp, skb, first_entry, entry); + goto out_dma_error; + } + eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0; ctrl = eor | len | DescOwn; @@ -859,11 +892,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb, if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); +out_unlock: spin_unlock_irqrestore(&cp->lock, intr_flags); cpw8(TxPoll, NormalTxPoll); return NETDEV_TX_OK; +out_dma_error: + kfree_skb(skb); + cp->dev->stats.tx_dropped++; + goto out_unlock; } /* Set or clear the multicast filter for this adaptor. @@ -1054,6 +1092,10 @@ static int cp_refill_rx(struct cp_private *cp) mapping = dma_map_single(&cp->pdev->dev, skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&cp->pdev->dev, mapping)) { + kfree_skb(skb); + goto err_out; + } cp->rx_skb[i] = skb; cp->rx_ring[i].opts2 = 0; -- cgit v0.10.2 From b00589af3b04736376f24625ab0b394642e89e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20L=C3=BCssing?= Date: Thu, 1 Aug 2013 01:06:20 +0200 Subject: bridge: disable snooping if there is no querier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is no querier on a link then we won't get periodic reports and therefore won't be able to learn about multicast listeners behind ports, potentially leading to lost multicast packets, especially for multicast listeners that joined before the creation of the bridge. These lost multicast packets can appear since c5c23260594 ("bridge: Add multicast_querier toggle and disable queries by default") in particular. With this patch we are flooding multicast packets if our querier is disabled and if we didn't detect any other querier. A grace period of the Maximum Response Delay of the querier is added to give multicast responses enough time to arrive and to be learned from before disabling the flooding behaviour again. Signed-off-by: Linus Lüssing Signed-off-by: David S. Miller diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 2ef6678..69363bd 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -70,7 +70,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) } mdst = br_mdb_get(br, skb, vid); - if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(br)) br_multicast_deliver(mdst, skb); else br_flood_deliver(br, skb, false); diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 1b8b8b8..8c561c0 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -101,7 +101,8 @@ int br_handle_frame_finish(struct sk_buff *skb) unicast = false; } else if (is_multicast_ether_addr(dest)) { mdst = br_mdb_get(br, skb, vid); - if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) { + if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && + br_multicast_querier_exists(br)) { if ((mdst && mdst->mglist) || br_multicast_is_router(br)) skb2 = skb; diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 4b99c9a..61c5e81 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -1014,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br, } #endif +static void br_multicast_update_querier_timer(struct net_bridge *br, + unsigned long max_delay) +{ + if (!timer_pending(&br->multicast_querier_timer)) + br->multicast_querier_delay_time = jiffies + max_delay; + + mod_timer(&br->multicast_querier_timer, + jiffies + br->multicast_querier_interval); +} + /* * Add port to router_list * list is maintained ordered by pointer value @@ -1064,11 +1074,11 @@ timer: static void br_multicast_query_received(struct net_bridge *br, struct net_bridge_port *port, - int saddr) + int saddr, + unsigned long max_delay) { if (saddr) - mod_timer(&br->multicast_querier_timer, - jiffies + br->multicast_querier_interval); + br_multicast_update_querier_timer(br, max_delay); else if (timer_pending(&br->multicast_querier_timer)) return; @@ -1096,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br, (port && port->state == BR_STATE_DISABLED)) goto out; - br_multicast_query_received(br, port, !!iph->saddr); - group = ih->group; if (skb->len == sizeof(*ih)) { @@ -1121,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br, IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; } + br_multicast_query_received(br, port, !!iph->saddr, max_delay); + if (!group) goto out; @@ -1176,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, (port && port->state == BR_STATE_DISABLED)) goto out; - br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr)); - if (skb->len == sizeof(*mld)) { if (!pskb_may_pull(skb, sizeof(*mld))) { err = -EINVAL; @@ -1198,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br, max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1; } + br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr), + max_delay); + if (!group) goto out; @@ -1643,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br) br->multicast_querier_interval = 255 * HZ; br->multicast_membership_interval = 260 * HZ; + br->multicast_querier_delay_time = 0; + spin_lock_init(&br->multicast_lock); setup_timer(&br->multicast_router_timer, br_multicast_local_router_expired, 0); @@ -1831,6 +1844,8 @@ unlock: int br_multicast_set_querier(struct net_bridge *br, unsigned long val) { + unsigned long max_delay; + val = !!val; spin_lock_bh(&br->multicast_lock); @@ -1838,8 +1853,14 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val) goto unlock; br->multicast_querier = val; - if (val) - br_multicast_start_querier(br); + if (!val) + goto unlock; + + max_delay = br->multicast_query_response_interval; + if (!timer_pending(&br->multicast_querier_timer)) + br->multicast_querier_delay_time = jiffies + max_delay; + + br_multicast_start_querier(br); unlock: spin_unlock_bh(&br->multicast_lock); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 3be89b3..2f7da41 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -267,6 +267,7 @@ struct net_bridge unsigned long multicast_query_interval; unsigned long multicast_query_response_interval; unsigned long multicast_startup_query_interval; + unsigned long multicast_querier_delay_time; spinlock_t multicast_lock; struct net_bridge_mdb_htable __rcu *mdb; @@ -501,6 +502,13 @@ static inline bool br_multicast_is_router(struct net_bridge *br) (br->multicast_router == 1 && timer_pending(&br->multicast_router_timer)); } + +static inline bool br_multicast_querier_exists(struct net_bridge *br) +{ + return time_is_before_jiffies(br->multicast_querier_delay_time) && + (br->multicast_querier || + timer_pending(&br->multicast_querier_timer)); +} #else static inline int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port, @@ -557,6 +565,10 @@ static inline bool br_multicast_is_router(struct net_bridge *br) { return 0; } +static inline bool br_multicast_querier_exists(struct net_bridge *br) +{ + return false; +} static inline void br_mdb_init(void) { } -- cgit v0.10.2 From e8e813ed268d90c1377f53460527c419eb52c67a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 4 Jun 2013 14:21:17 +1000 Subject: powerpc: Rename PMU interrupts from CNT to PMI Back in commit 89713ed "Add timer, performance monitor and machine check counts to /proc/interrupts" we added a count of PMU interrupts to the output of /proc/interrupts. At the time we named them "CNT" to match x86. However in commit 89ccf46 "Rename 'performance counter interrupt'", the x86 guys renamed theirs from "CNT" to "PMI". Arguably changing the name could break someone's script, but I think the chance of that is minimal, and it's preferable to have a name that 1) is somewhat meaningful, and 2) matches x86. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 2e51cde..c69440c 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -362,7 +362,7 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs); seq_printf(p, " Spurious interrupts\n"); - seq_printf(p, "%*s: ", prec, "CNT"); + seq_printf(p, "%*s: ", prec, "PMI"); for_each_online_cpu(j) seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs); seq_printf(p, " Performance monitoring interrupts\n"); -- cgit v0.10.2 From 8d7c55d01e4648605fd0dacc82d8d3989ead4db7 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 23 Jul 2013 18:07:45 +1000 Subject: powerpc/perf: Export PERF_EVENT_CONFIG_EBB_SHIFT to userspace We use bit 63 of the event code for userspace to request that the event be counted using EBB (Event Based Branches). Export this value, making it part of the API - though only on processors that support EBB. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 2dd7bfc..8b24926 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -12,6 +12,7 @@ #include #include #include +#include #define MAX_HWEVENTS 8 #define MAX_EVENT_ALTERNATIVES 8 @@ -69,11 +70,6 @@ struct power_pmu { #define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */ #define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */ -/* - * We use the event config bit 63 as a flag to request EBB. - */ -#define EVENT_CONFIG_EBB_SHIFT 63 - extern int register_power_pmu(struct power_pmu *); struct pt_regs; diff --git a/arch/powerpc/include/uapi/asm/Kbuild b/arch/powerpc/include/uapi/asm/Kbuild index 5182c86..48be855 100644 --- a/arch/powerpc/include/uapi/asm/Kbuild +++ b/arch/powerpc/include/uapi/asm/Kbuild @@ -20,6 +20,7 @@ header-y += mman.h header-y += msgbuf.h header-y += nvram.h header-y += param.h +header-y += perf_event.h header-y += poll.h header-y += posix_types.h header-y += ps3fb.h diff --git a/arch/powerpc/include/uapi/asm/perf_event.h b/arch/powerpc/include/uapi/asm/perf_event.h new file mode 100644 index 0000000..80a4d40 --- /dev/null +++ b/arch/powerpc/include/uapi/asm/perf_event.h @@ -0,0 +1,18 @@ +/* + * Copyright 2013 Michael Ellerman, IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 of the + * License. + */ + +#ifndef _UAPI_ASM_POWERPC_PERF_EVENT_H +#define _UAPI_ASM_POWERPC_PERF_EVENT_H + +/* + * We use bit 63 of perf_event_attr.config as a flag to request EBB. + */ +#define PERF_EVENT_CONFIG_EBB_SHIFT 63 + +#endif /* _UAPI_ASM_POWERPC_PERF_EVENT_H */ diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 24a45f9..eeae308 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -484,7 +484,7 @@ static bool is_ebb_event(struct perf_event *event) * use bit 63 of the event code for something else if they wish. */ return (ppmu->flags & PPMU_EBB) && - ((event->attr.config >> EVENT_CONFIG_EBB_SHIFT) & 1); + ((event->attr.config >> PERF_EVENT_CONFIG_EBB_SHIFT) & 1); } static int ebb_event_check(struct perf_event *event) diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c index 7466374..2ee4a70 100644 --- a/arch/powerpc/perf/power8-pmu.c +++ b/arch/powerpc/perf/power8-pmu.c @@ -118,7 +118,7 @@ (EVENT_UNIT_MASK << EVENT_UNIT_SHIFT) | \ (EVENT_COMBINE_MASK << EVENT_COMBINE_SHIFT) | \ (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT) | \ - (EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT) | \ + (EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT) | \ EVENT_PSEL_MASK) /* MMCRA IFM bits - POWER8 */ @@ -233,10 +233,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK; unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK; cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK; - ebb = (event >> EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK; + ebb = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK; /* Clear the EBB bit in the event, so event checks work below */ - event &= ~(EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT); + event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT); if (pmc) { if (pmc > 6) -- cgit v0.10.2 From 3be7db6ab45b21345386d1a466da133b19cde5e4 Mon Sep 17 00:00:00 2001 From: Robert Jennings Date: Wed, 24 Jul 2013 20:13:21 -0500 Subject: powerpc: VPHN topology change updates all siblings When an associativity level change is found for one thread, the siblings threads need to be updated as well. This is done today for PRRN in stage_topology_update() but is missing for VPHN in update_cpu_associativity_changes_mask(). This patch will correctly update all thread siblings during a topology change. Without this patch a topology update can result in a CPU in init_sched_groups_power() getting stuck indefinitely in a loop. This loop is built in build_sched_groups(). As a result of the thread moving to a node separate from its siblings the struct sched_group will have its next pointer set to point to itself rather than the sched_group struct of the next thread. This happens because we have a domain without the SD_OVERLAP flag, which is correct, and a topology that doesn't conform with reality (threads on the same core assigned to different numa nodes). When this list is traversed by init_sched_groups_power() it will reach the thread's sched_group structure and loop indefinitely; the cpu will be stuck at this point. The bug was exposed when VPHN was enabled in commit b7abef0 (v3.9). Cc: [v3.9+] Reported-by: Jan Stancek Signed-off-by: Robert Jennings Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index ffbaabe..48cfc85 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -145,6 +145,10 @@ extern void __cpu_die(unsigned int cpu); #define smp_setup_cpu_maps() static inline void inhibit_secondary_onlining(void) {} static inline void uninhibit_secondary_onlining(void) {} +static inline const struct cpumask *cpu_sibling_mask(int cpu) +{ + return cpumask_of(cpu); +} #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 0839721..5850798 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1318,7 +1319,8 @@ static int update_cpu_associativity_changes_mask(void) } } if (changed) { - cpumask_set_cpu(cpu, changes); + cpumask_or(changes, changes, cpu_sibling_mask(cpu)); + cpu = cpu_last_thread_sibling(cpu); } } @@ -1426,7 +1428,7 @@ static int update_cpu_topology(void *data) if (!data) return -EINVAL; - cpu = get_cpu(); + cpu = smp_processor_id(); for (update = data; update; update = update->next) { if (cpu != update->cpu) @@ -1446,12 +1448,12 @@ static int update_cpu_topology(void *data) */ int arch_update_cpu_topology(void) { - unsigned int cpu, changed = 0; + unsigned int cpu, sibling, changed = 0; struct topology_update_data *updates, *ud; unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0}; cpumask_t updated_cpus; struct device *dev; - int weight, i = 0; + int weight, new_nid, i = 0; weight = cpumask_weight(&cpu_associativity_changes_mask); if (!weight) @@ -1464,19 +1466,46 @@ int arch_update_cpu_topology(void) cpumask_clear(&updated_cpus); for_each_cpu(cpu, &cpu_associativity_changes_mask) { - ud = &updates[i++]; - ud->cpu = cpu; - vphn_get_associativity(cpu, associativity); - ud->new_nid = associativity_to_nid(associativity); - - if (ud->new_nid < 0 || !node_online(ud->new_nid)) - ud->new_nid = first_online_node; + /* + * If siblings aren't flagged for changes, updates list + * will be too short. Skip on this update and set for next + * update. + */ + if (!cpumask_subset(cpu_sibling_mask(cpu), + &cpu_associativity_changes_mask)) { + pr_info("Sibling bits not set for associativity " + "change, cpu%d\n", cpu); + cpumask_or(&cpu_associativity_changes_mask, + &cpu_associativity_changes_mask, + cpu_sibling_mask(cpu)); + cpu = cpu_last_thread_sibling(cpu); + continue; + } - ud->old_nid = numa_cpu_lookup_table[cpu]; - cpumask_set_cpu(cpu, &updated_cpus); + /* Use associativity from first thread for all siblings */ + vphn_get_associativity(cpu, associativity); + new_nid = associativity_to_nid(associativity); + if (new_nid < 0 || !node_online(new_nid)) + new_nid = first_online_node; + + if (new_nid == numa_cpu_lookup_table[cpu]) { + cpumask_andnot(&cpu_associativity_changes_mask, + &cpu_associativity_changes_mask, + cpu_sibling_mask(cpu)); + cpu = cpu_last_thread_sibling(cpu); + continue; + } - if (i < weight) - ud->next = &updates[i]; + for_each_cpu(sibling, cpu_sibling_mask(cpu)) { + ud = &updates[i++]; + ud->cpu = sibling; + ud->new_nid = new_nid; + ud->old_nid = numa_cpu_lookup_table[sibling]; + cpumask_set_cpu(sibling, &updated_cpus); + if (i < weight) + ud->next = &updates[i]; + } + cpu = cpu_last_thread_sibling(cpu); } stop_machine(update_cpu_topology, &updates[0], &updated_cpus); -- cgit v0.10.2 From fe956a1d4081ce1a959f87df397a15e252201f10 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 21 Jul 2013 03:30:11 +0300 Subject: powerpc/windfarm: Fix noisy slots-fan on Xserve (rm31) slots-fan on G5 Xserve is always running at full speed with windfarm_rm31 driver, resulting in a very high acoustic noise level. It seems the fan parameters are incorrect, and have been copied from the Drive Bay fan (RPM, not present on rm31) of the legacy therm_pm72 driver. This patch changes the parameters to match the Slots fan (PWM) of therm_pm72. With the patch, slots-fan speed drops from 99% to 19% during normal use, and slots-temp settle to ~42'C. Signed-off-by: Aaro Koskinen CC: Signed-off-by: Benjamin Herrenschmidt diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c index 0b9a79b..82fc86a 100644 --- a/drivers/macintosh/windfarm_rm31.c +++ b/drivers/macintosh/windfarm_rm31.c @@ -439,15 +439,15 @@ static void backside_setup_pid(void) /* Slots fan */ static const struct wf_pid_param slots_param = { - .interval = 5, - .history_len = 2, - .gd = 30 << 20, - .gp = 5 << 20, - .gr = 0, - .itarget = 40 << 16, - .additive = 1, - .min = 300, - .max = 4000, + .interval = 1, + .history_len = 20, + .gd = 0, + .gp = 0, + .gr = 0x00100000, + .itarget = 3200000, + .additive = 0, + .min = 20, + .max = 100, }; static void slots_fan_tick(void) -- cgit v0.10.2 From 447383d2ba6061bb069da45f95f223a01bba61dd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 25 Jul 2013 11:30:23 +1000 Subject: NFSD/sunrpc: avoid deadlock on TCP connection due to memory pressure. Since we enabled auto-tuning for sunrpc TCP connections we do not guarantee that there is enough write-space on each connection to queue a reply. If memory pressure causes the window to shrink too small, the request throttling in sunrpc/svc will not accept any requests so no more requests will be handled. Even when pressure decreases the window will not grow again until data is sent on the connection. This means we get a deadlock: no requests will be handled until there is more space, and no space will be allocated until a request is handled. This can be simulated by modifying svc_tcp_has_wspace to inflate the number of byte required and removing the 'svc_sock_setbufsize' calls in svc_setup_socket. I found that multiplying by 16 was enough to make the requirement exceed the default allocation. With this modification in place: mount -o vers=3,proto=tcp 127.0.0.1:/home /mnt would block and eventually time out because the nfs server could not accept any requests. This patch relaxes the request throttling to always allow at least one request through per connection. It does this by checking both sk_stream_min_wspace() and xprt->xpt_reserved are zero. The first is zero when the TCP transmit queue is empty. The second is zero when there are no RPC requests being processed. When both of these are zero the socket is idle and so one more request can safely be allowed through. Applying this patch allows the above mount command to succeed cleanly. Tracing shows that the allocated write buffer space quickly grows and after a few requests are handled, the extra tests are no longer needed to permit further requests to be processed. The main purpose of request throttling is to handle the case when one client is slow at collecting replies and the send queue gets full of replies that the client hasn't acknowledged (at the TCP level) yet. As we only change behaviour when the send queue is empty this main purpose is still preserved. Reported-by: Ben Myers Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 305374d..7762b9f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1193,7 +1193,9 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt) if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) return 1; required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; - if (sk_stream_wspace(svsk->sk_sk) >= required) + if (sk_stream_wspace(svsk->sk_sk) >= required || + (sk_stream_min_wspace(svsk->sk_sk) == 0 && + atomic_read(&xprt->xpt_reserved) == 0)) return 1; set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); return 0; -- cgit v0.10.2 From 9f96392b0ae6aefc02a9b900c3f4889dfafc8402 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 10 Jun 2013 16:06:44 -0400 Subject: svcrpc: fix gss_rpc_upcall create error Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index d304f41..1e1ccf5 100644 --- a/net/sunrpc/auth_gss/gss_rpc_upcall.c +++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c @@ -120,7 +120,7 @@ static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt) if (IS_ERR(clnt)) { dprintk("RPC: failed to create AF_LOCAL gssproxy " "client (errno %ld).\n", PTR_ERR(clnt)); - result = -PTR_ERR(clnt); + result = PTR_ERR(clnt); *_clnt = NULL; goto out; } -- cgit v0.10.2 From dc43376c26cef74226174a2394f37f2a3f8a8639 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 7 Jun 2013 10:11:19 -0400 Subject: svcrpc: fix gss-proxy xdr decoding oops Uninitialized stack data was being used as the destination for memcpy's. Longer term we'll just delete some of this code; all we're doing is skipping over xdr that we don't care about. Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c index 357f613..3c85d1c 100644 --- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -430,7 +430,7 @@ static int dummy_enc_nameattr_array(struct xdr_stream *xdr, static int dummy_dec_nameattr_array(struct xdr_stream *xdr, struct gssx_name_attr_array *naa) { - struct gssx_name_attr dummy; + struct gssx_name_attr dummy = { .attr = {.len = 0} }; u32 count, i; __be32 *p; @@ -493,12 +493,13 @@ static int gssx_enc_name(struct xdr_stream *xdr, return err; } + static int gssx_dec_name(struct xdr_stream *xdr, struct gssx_name *name) { - struct xdr_netobj dummy_netobj; - struct gssx_name_attr_array dummy_name_attr_array; - struct gssx_option_array dummy_option_array; + struct xdr_netobj dummy_netobj = { .len = 0 }; + struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 }; + struct gssx_option_array dummy_option_array = { .count = 0 }; int err; /* name->display_name */ -- cgit v0.10.2 From 743e217129f69aab074abe520a464fd0c6b1cca1 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 31 Jul 2013 14:11:14 -0400 Subject: svcrpc: fix kfree oops in gss-proxy code mech_oid.data is an array, not kmalloc()'d memory. Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c index 1e1ccf5..af7ffd4 100644 --- a/net/sunrpc/auth_gss/gss_rpc_upcall.c +++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c @@ -328,7 +328,6 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data) kfree(data->in_handle.data); kfree(data->out_handle.data); kfree(data->out_token.data); - kfree(data->mech_oid.data); free_svc_cred(&data->creds); } -- cgit v0.10.2 From 7193bd17ea92c4c89016c304362c9be93ce50050 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 31 Jul 2013 17:51:42 -0400 Subject: svcrpc: set cr_gss_mech from gss-proxy as well as legacy upcall The change made to rsc_parse() in 0dc1531aca7fd1440918bd55844a054e9c29acad "svcrpc: store gss mech in svc_cred" should also have been propagated to the gss-proxy codepath. This fixes a crash in the gss-proxy case. Signed-off-by: J. Bruce Fields diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index d0347d1..09fb638 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1180,6 +1180,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, gm = gss_mech_get_by_OID(&ud->mech_oid); if (!gm) goto out; + rsci.cred.cr_gss_mech = gm; status = -EINVAL; /* mech-specific data: */ @@ -1195,7 +1196,6 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, rscp = rsc_update(cd, &rsci, rscp); status = 0; out: - gss_mech_put(gm); rsc_free(&rsci); if (rscp) cache_put(&rscp->h, cd); -- cgit v0.10.2 From 48be69a026b2c17350a5ef18a1959a919f60be7d Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 24 Jul 2013 00:29:18 +0100 Subject: ARM: move signal handlers into a vdso-like page Move the signal handlers into a VDSO page rather than keeping them in the vectors page. This allows us to place them randomly within this page, and also map the page at a random location within userspace further protecting these code fragments from ROP attacks. The new VDSO page is also poisoned in the same way as the vector page. Signed-off-by: Russell King diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 38050b1..9c9b307 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -130,4 +130,8 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +struct linux_binprm; +int arch_setup_additional_pages(struct linux_binprm *, int); + #endif diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index e3d5554..7345e37 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -8,6 +8,7 @@ typedef struct { atomic64_t id; #endif unsigned int vmalloc_seq; + unsigned long sigpage; } mm_context_t; #ifdef CONFIG_CPU_HAS_ASID diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index d3ca4f6..566d0d7 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -428,8 +428,8 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) #ifdef CONFIG_MMU /* * The vectors page is always readable from user space for the - * atomic helpers and the signal restart code. Insert it into the - * gate_vma so that it is visible through ptrace and /proc//mem. + * atomic helpers. Insert it into the gate_vma so that it is visible + * through ptrace and /proc//mem. */ static struct vm_area_struct gate_vma = { .vm_start = 0xffff0000, @@ -461,6 +461,40 @@ int in_gate_area_no_mm(unsigned long addr) const char *arch_vma_name(struct vm_area_struct *vma) { - return (vma == &gate_vma) ? "[vectors]" : NULL; + return (vma == &gate_vma) ? "[vectors]" : + (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ? + "[sigpage]" : NULL; +} + +extern struct page *get_signal_page(void); + +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current->mm; + struct page *page; + unsigned long addr; + int ret; + + page = get_signal_page(); + if (!page) + return -ENOMEM; + + down_write(&mm->mmap_sem); + addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); + if (IS_ERR_VALUE(addr)) { + ret = addr; + goto up_fail; + } + + ret = install_special_mapping(mm, addr, PAGE_SIZE, + VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, + &page); + + if (ret == 0) + mm->context.sigpage = addr; + + up_fail: + up_write(&mm->mmap_sem); + return ret; } #endif diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 1c16c35..0f17e06 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include @@ -15,12 +16,11 @@ #include #include +#include #include #include #include -#include "signal.h" - /* * For ARM syscalls, we encode the syscall number into the instruction. */ @@ -40,11 +40,13 @@ #define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE)) #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE)) -const unsigned long sigreturn_codes[7] = { +static const unsigned long sigreturn_codes[7] = { MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; +static unsigned long signal_return_offset; + #ifdef CONFIG_CRUNCH static int preserve_crunch_context(struct crunch_sigframe __user *frame) { @@ -401,12 +403,15 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, return 1; if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) { + struct mm_struct *mm = current->mm; + /* - * 32-bit code can use the new high-page - * signal return code support except when the MPU has - * protected the vectors page from PL0 + * 32-bit code can use the signal return page + * except when the MPU has protected the vectors + * page from PL0 */ - retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb; + retcode = mm->context.sigpage + signal_return_offset + + (idx << 2) + thumb; } else { /* * Ensure that the instruction cache sees @@ -608,3 +613,36 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) } while (thread_flags & _TIF_WORK_MASK); return 0; } + +static struct page *signal_page; + +struct page *get_signal_page(void) +{ + if (!signal_page) { + unsigned long ptr; + unsigned offset; + void *addr; + + signal_page = alloc_pages(GFP_KERNEL, 0); + + if (!signal_page) + return NULL; + + addr = page_address(signal_page); + + /* Give the signal return code some randomness */ + offset = 0x200 + (get_random_int() & 0x7fc); + signal_return_offset = offset; + + /* + * Copy signal return handlers into the vector page, and + * set sigreturn to be a pointer to these. + */ + memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); + + ptr = (unsigned long)addr + offset; + flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); + } + + return signal_page; +} diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h deleted file mode 100644 index 5ff067b7..0000000 --- a/arch/arm/kernel/signal.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * linux/arch/arm/kernel/signal.h - * - * Copyright (C) 2005-2009 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) - -extern const unsigned long sigreturn_codes[7]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index e3ca35c..ab517fc 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -35,8 +35,6 @@ #include #include -#include "signal.h" - static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; void *vectors_page; @@ -850,13 +848,6 @@ void __init early_trap_init(void *vectors_base) kuser_init(vectors_base); - /* - * Copy signal return handlers into the vector page, and - * set sigreturn to be a pointer to these. - */ - memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), - sigreturn_codes, sizeof(sigreturn_codes)); - flush_icache_range(vectors, vectors + PAGE_SIZE * 2); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); #else /* ifndef CONFIG_CPU_V7M */ -- cgit v0.10.2 From a5463cd3435475386cbbe7b06e01292ac169d36f Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Jul 2013 21:58:56 +0100 Subject: ARM: make vectors page inaccessible from userspace If kuser helpers are not provided by the kernel, disable user access to the vectors page. With the kuser helpers gone, there is no reason for this page to be visible to userspace. Signed-off-by: Russell King diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 6363f3d..4355f0e 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -142,7 +142,9 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from, #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) extern void copy_page(void *to, const void *from); +#ifdef CONFIG_KUSER_HELPERS #define __HAVE_ARCH_GATE_AREA 1 +#endif #ifdef CONFIG_ARM_LPAE #include diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 566d0d7..1e6c33d 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -426,6 +426,7 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) } #ifdef CONFIG_MMU +#ifdef CONFIG_KUSER_HELPERS /* * The vectors page is always readable from user space for the * atomic helpers. Insert it into the gate_vma so that it is visible @@ -458,10 +459,14 @@ int in_gate_area_no_mm(unsigned long addr) { return in_gate_area(NULL, addr); } +#define is_gate_vma(vma) ((vma) = &gate_vma) +#else +#define is_gate_vma(vma) 0 +#endif const char *arch_vma_name(struct vm_area_struct *vma) { - return (vma == &gate_vma) ? "[vectors]" : + return is_gate_vma(vma) ? "[vectors]" : (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ? "[sigpage]" : NULL; } diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9ea274d..ca46f41 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1205,7 +1205,11 @@ static void __init devicemaps_init(struct machine_desc *mdesc) map.pfn = __phys_to_pfn(virt_to_phys(vectors)); map.virtual = 0xffff0000; map.length = PAGE_SIZE; +#ifdef CONFIG_KUSER_HELPERS map.type = MT_HIGH_VECTORS; +#else + map.type = MT_LOW_VECTORS; +#endif create_mapping(&map); if (!vectors_high()) { -- cgit v0.10.2 From 44424c34049f41123a3a8b4853822f47f4ff03a2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2013 23:09:46 +0100 Subject: ARM: 7803/1: Fix deadlock scenario with smp_send_stop() If one process calls sys_reboot and that process then stops other CPUs while those CPUs are within a spin_lock() region we can potentially encounter a deadlock scenario like below. CPU 0 CPU 1 ----- ----- spin_lock(my_lock) smp_send_stop() handle_IPI() disable_preemption/irqs while(1); spin_lock(my_lock) <--- Waits forever We shouldn't attempt to run any other tasks after we send a stop IPI to a CPU so disable preemption so that this task runs to completion. We use local_irq_disable() here for cross-arch consistency with x86. Reported-by: Sundarajan Srinivasan Signed-off-by: Stephen Boyd Signed-off-by: Russell King diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index d3ca4f6..08b47eb 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -197,6 +197,7 @@ void machine_shutdown(void) */ void machine_halt(void) { + local_irq_disable(); smp_send_stop(); local_irq_disable(); @@ -211,6 +212,7 @@ void machine_halt(void) */ void machine_power_off(void) { + local_irq_disable(); smp_send_stop(); if (pm_power_off) @@ -230,6 +232,7 @@ void machine_power_off(void) */ void machine_restart(char *cmd) { + local_irq_disable(); smp_send_stop(); arm_pm_restart(reboot_mode, cmd); -- cgit v0.10.2 From 2449189bb7c73b5fe55a18bc0d289e39bdcd4998 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 31 Jul 2013 11:37:17 +0100 Subject: ARM: Add .text annotations where required after __CPUINIT removal Commit 8bd26e3a7 (arm: delete __cpuinit/__CPUINIT usage from all ARM users) caused some code to leak into sections which are discarded through the removal of __CPUINIT annotations. Add appropriate .text annotations to bring these back into the kernel text. Signed-off-by: Russell King diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index b361de1..14235ba 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -87,6 +87,7 @@ ENTRY(stext) ENDPROC(stext) #ifdef CONFIG_SMP + .text ENTRY(secondary_startup) /* * Common entry point for secondary CPUs. diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 9cf6063..2c7cc1e 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -343,6 +343,7 @@ __turn_mmu_on_loc: .long __turn_mmu_on_end #if defined(CONFIG_SMP) + .text ENTRY(secondary_startup) /* * Common entry point for secondary CPUs. -- cgit v0.10.2 From 36dd1f3e02a4aed850a7b7318d7abd4f4d50528c Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 1 Aug 2013 15:44:19 +0200 Subject: PCI: mvebu: Disable prefetchable memory support in PCI-to-PCI bridge The Marvell PCIe driver uses an emulated PCI-to-PCI bridge to be able to dynamically set up MBus address decoding windows for PCI I/O and memory regions depending on the PCI devices enumerated by Linux. However, this emulated PCI-to-PCI bridge logic makes the Linux PCI core believe that prefetchable memory regions are supported (because the registers are read/write), while in fact no adress decoding window is ever created for such regions. Since the Marvell MBus address decoding windows do not distinguish memory regions and prefetchable memory regions, this patch takes a simple approach: change the PCI-to-PCI bridge emulation to let the Linux PCI core know that we don't support prefetchable memory regions. To achieve this, we simply make the prefetchable memory base a read-only register that always returns 0. Reading/writing all the other prefetchable memory related registers has no effect. This problem was originally reported by Finn Hoffmann , who couldn't get a RTL8111/8168B PCI NIC working on the NSA310 Kirkwood platform after updating to 3.11-rc. The problem was that the PCI-to-PCI bridge emulation was making the Linux PCI core believe that we support prefetchable memory, so the Linux PCI core was only filling the prefetchable memory base and limit registers, which does not lead to a MBus window being created. The below patch has been confirmed by Finn Hoffmann to fix his problem on Kirkwood, and has otherwise been successfully tested on the Armada XP GP platform with a e1000e PCIe NIC and a Marvell SATA PCIe card. Reported-by: Finn Hoffmann Signed-off-by: Thomas Petazzoni Signed-off-by: Bjorn Helgaas diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 13a633b..7bf3926 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge { u16 secondary_status; u16 membase; u16 memlimit; - u16 prefmembase; - u16 prefmemlimit; - u32 prefbaseupper; - u32 preflimitupper; u16 iobaseupper; u16 iolimitupper; u8 cappointer; @@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port, break; case PCI_PREF_MEMORY_BASE: - *value = (bridge->prefmemlimit << 16 | bridge->prefmembase); - break; - - case PCI_PREF_BASE_UPPER32: - *value = bridge->prefbaseupper; - break; - - case PCI_PREF_LIMIT_UPPER32: - *value = bridge->preflimitupper; + *value = 0; break; case PCI_IO_BASE_UPPER16: @@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port, mvebu_pcie_handle_membase_change(port); break; - case PCI_PREF_MEMORY_BASE: - bridge->prefmembase = value & 0xffff; - bridge->prefmemlimit = value >> 16; - break; - - case PCI_PREF_BASE_UPPER32: - bridge->prefbaseupper = value; - break; - - case PCI_PREF_LIMIT_UPPER32: - bridge->preflimitupper = value; - break; - case PCI_IO_BASE_UPPER16: bridge->iobaseupper = value & 0xffff; bridge->iolimitupper = value >> 16; -- cgit v0.10.2 From 2ac3ac8f86f2fe065d746d9a9abaca867adec577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Thu, 1 Aug 2013 10:04:14 +0200 Subject: ipv6: prevent fib6_run_gc() contention On a high-traffic router with many processors and many IPv6 dst entries, soft lockup in fib6_run_gc() can occur when number of entries reaches gc_thresh. This happens because fib6_run_gc() uses fib6_gc_lock to allow only one thread to run the garbage collector but ip6_dst_gc() doesn't update net->ipv6.ip6_rt_last_gc until fib6_run_gc() returns. On a system with many entries, this can take some time so that in the meantime, other threads pass the tests in ip6_dst_gc() (ip6_rt_last_gc is still not updated) and wait for the lock. They then have to run the garbage collector one after another which blocks them for quite long. Resolve this by replacing special value ~0UL of expire parameter to fib6_run_gc() by explicit "force" parameter to choose between spin_lock_bh() and spin_trylock_bh() and call fib6_run_gc() with force=false if gc_thresh is reached but not max_size. Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 2a601e7..48ec25a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -300,7 +300,7 @@ extern void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info); extern void fib6_run_gc(unsigned long expires, - struct net *net); + struct net *net, bool force); extern void fib6_gc_cleanup(void); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 5fc9c7a..d872553 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1632,19 +1632,16 @@ static int fib6_age(struct rt6_info *rt, void *arg) static DEFINE_SPINLOCK(fib6_gc_lock); -void fib6_run_gc(unsigned long expires, struct net *net) +void fib6_run_gc(unsigned long expires, struct net *net, bool force) { - if (expires != ~0UL) { + if (force) { spin_lock_bh(&fib6_gc_lock); - gc_args.timeout = expires ? (int)expires : - net->ipv6.sysctl.ip6_rt_gc_interval; - } else { - if (!spin_trylock_bh(&fib6_gc_lock)) { - mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); - return; - } - gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval; + } else if (!spin_trylock_bh(&fib6_gc_lock)) { + mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); + return; } + gc_args.timeout = expires ? (int)expires : + net->ipv6.sysctl.ip6_rt_gc_interval; gc_args.more = icmp6_dst_gc(); @@ -1661,7 +1658,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) static void fib6_gc_timer_cb(unsigned long arg) { - fib6_run_gc(0, (struct net *)arg); + fib6_run_gc(0, (struct net *)arg, true); } static int __net_init fib6_net_init(struct net *net) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 24c03396..79aa965 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1576,7 +1576,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); - fib6_run_gc(~0UL, net); + fib6_run_gc(0, net, false); idev = in6_dev_get(dev); if (!idev) break; @@ -1586,7 +1586,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, break; case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); - fib6_run_gc(~0UL, net); + fib6_run_gc(0, net, false); break; case NETDEV_NOTIFY_PEERS: ndisc_send_unsol_na(dev); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a8c891a..824c424 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1326,7 +1326,7 @@ static int ip6_dst_gc(struct dst_ops *ops) goto out; net->ipv6.ip6_rt_gc_expire++; - fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); + fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size); net->ipv6.ip6_rt_last_gc = now; entries = dst_entries_get_slow(ops); if (entries < ops->gc_thresh) @@ -2827,7 +2827,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write, net = (struct net *)ctl->extra1; delay = net->ipv6.sysctl.flush_delay; proc_dointvec(ctl, write, buffer, lenp, ppos); - fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); + fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0); return 0; } -- cgit v0.10.2 From 49a18d86f66d33a20144ecb5a34bba0d1856b260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Thu, 1 Aug 2013 10:04:24 +0200 Subject: ipv6: update ip6_rt_last_gc every time GC is run As pointed out by Eric Dumazet, net->ipv6.ip6_rt_last_gc should hold the last time garbage collector was run so that we should update it whenever fib6_run_gc() calls fib6_clean_all(), not only if we got there from ip6_dst_gc(). Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index d872553..bff3d82 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1634,6 +1634,8 @@ static DEFINE_SPINLOCK(fib6_gc_lock); void fib6_run_gc(unsigned long expires, struct net *net, bool force) { + unsigned long now; + if (force) { spin_lock_bh(&fib6_gc_lock); } else if (!spin_trylock_bh(&fib6_gc_lock)) { @@ -1646,10 +1648,12 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force) gc_args.more = icmp6_dst_gc(); fib6_clean_all(net, fib6_age, 0, NULL); + now = jiffies; + net->ipv6.ip6_rt_last_gc = now; if (gc_args.more) mod_timer(&net->ipv6.ip6_fib_timer, - round_jiffies(jiffies + round_jiffies(now + net->ipv6.sysctl.ip6_rt_gc_interval)); else del_timer(&net->ipv6.ip6_fib_timer); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 824c424..b70f897 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1311,7 +1311,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg), static int ip6_dst_gc(struct dst_ops *ops) { - unsigned long now = jiffies; struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; @@ -1321,13 +1320,12 @@ static int ip6_dst_gc(struct dst_ops *ops) int entries; entries = dst_entries_get_fast(ops); - if (time_after(rt_last_gc + rt_min_interval, now) && + if (time_after(rt_last_gc + rt_min_interval, jiffies) && entries <= rt_max_size) goto out; net->ipv6.ip6_rt_gc_expire++; fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size); - net->ipv6.ip6_rt_last_gc = now; entries = dst_entries_get_slow(ops); if (entries < ops->gc_thresh) net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; -- cgit v0.10.2 From 3f8f52982ad020f0704548c46de66bf464d3b967 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Aug 2013 10:41:27 +0200 Subject: ipv6: move peer_addr init into ipv6_add_addr() Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cfdcf7b..a0ce957 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -813,7 +813,8 @@ static u32 inet6_addr_hash(const struct in6_addr *addr) /* On success it returns ifp with increased reference count */ static struct inet6_ifaddr * -ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, +ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, + const struct in6_addr *peer_addr, int pfxlen, int scope, u32 flags) { struct inet6_ifaddr *ifa = NULL; @@ -863,6 +864,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, } ifa->addr = *addr; + if (peer_addr) + ifa->peer_addr = *peer_addr; spin_lock_init(&ifa->lock); spin_lock_init(&ifa->state_lock); @@ -1123,8 +1126,8 @@ retry: ift = !max_addresses || ipv6_count_addresses(idev) < max_addresses ? - ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr), - addr_flags) : NULL; + ipv6_add_addr(idev, &addr, NULL, tmp_plen, + ipv6_addr_scope(&addr), addr_flags) : NULL; if (IS_ERR_OR_NULL(ift)) { in6_ifa_put(ifp); in6_dev_put(idev); @@ -2179,7 +2182,8 @@ ok: */ if (!max_addresses || ipv6_count_addresses(in6_dev) < max_addresses) - ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, + ifp = ipv6_add_addr(in6_dev, &addr, NULL, + pinfo->prefix_len, addr_type&IPV6_ADDR_SCOPE_MASK, addr_flags); @@ -2455,15 +2459,13 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p prefered_lft = timeout; } - ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); + ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->valid_lft = valid_lft; ifp->prefered_lft = prefered_lft; ifp->tstamp = jiffies; - if (peer_pfx) - ifp->peer_addr = *peer_pfx; spin_unlock_bh(&ifp->lock); addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, @@ -2557,7 +2559,7 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, { struct inet6_ifaddr *ifp; - ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, addr, NULL, plen, scope, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; @@ -2683,7 +2685,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr #endif - ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); + ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags); if (!IS_ERR(ifp)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); addrconf_dad_start(ifp); -- cgit v0.10.2 From 8a226b2cfa776db6011fc84b71578513161cd3d3 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 1 Aug 2013 10:41:28 +0200 Subject: ipv6: prevent race between address creation and removal There's a race in IPv6 automatic addess assignment. The address is created with zero lifetime when it's added to various address lists. Before it gets assigned the correct lifetime, there's a window where a new address may be configured. This causes the semi-initiated address to be deleted in addrconf_verify. This was discovered as a reference leak caused by concurrent run of __ipv6_ifa_notify for both RTM_NEWADDR and RTM_DELADDR with the same address. Fix this by setting the lifetime before the address is added to inet6_addr_lst. A few notes: 1. In addrconf_prefix_rcv, by setting update_lft to zero, the if (update_lft) { ... } condition is no longer executed for newly created addresses. This is okay, as the ifp fields are set in ipv6_add_addr now and ipv6_ifa_notify is called (and has been called) through addrconf_dad_start. 2. The removal of the whole block under ifp->lock in inet6_addr_add is okay, too, as tstamp is initialized to jiffies in ipv6_add_addr. Signed-off-by: Jiri Benc Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a0ce957..da4241c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -815,7 +815,7 @@ static u32 inet6_addr_hash(const struct in6_addr *addr) static struct inet6_ifaddr * ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, const struct in6_addr *peer_addr, int pfxlen, - int scope, u32 flags) + int scope, u32 flags, u32 valid_lft, u32 prefered_lft) { struct inet6_ifaddr *ifa = NULL; struct rt6_info *rt; @@ -875,6 +875,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, ifa->scope = scope; ifa->prefix_len = pfxlen; ifa->flags = flags | IFA_F_TENTATIVE; + ifa->valid_lft = valid_lft; + ifa->prefered_lft = prefered_lft; ifa->cstamp = ifa->tstamp = jiffies; ifa->tokenized = false; @@ -1127,7 +1129,8 @@ retry: ift = !max_addresses || ipv6_count_addresses(idev) < max_addresses ? ipv6_add_addr(idev, &addr, NULL, tmp_plen, - ipv6_addr_scope(&addr), addr_flags) : NULL; + ipv6_addr_scope(&addr), addr_flags, + tmp_valid_lft, tmp_prefered_lft) : NULL; if (IS_ERR_OR_NULL(ift)) { in6_ifa_put(ifp); in6_dev_put(idev); @@ -1139,8 +1142,6 @@ retry: spin_lock_bh(&ift->lock); ift->ifpub = ifp; - ift->valid_lft = tmp_valid_lft; - ift->prefered_lft = tmp_prefered_lft; ift->cstamp = now; ift->tstamp = tmp_tstamp; spin_unlock_bh(&ift->lock); @@ -2185,14 +2186,16 @@ ok: ifp = ipv6_add_addr(in6_dev, &addr, NULL, pinfo->prefix_len, addr_type&IPV6_ADDR_SCOPE_MASK, - addr_flags); + addr_flags, valid_lft, + prefered_lft); if (IS_ERR_OR_NULL(ifp)) { in6_dev_put(in6_dev); return; } - update_lft = create = 1; + update_lft = 0; + create = 1; ifp->cstamp = jiffies; ifp->tokenized = tokenized; addrconf_dad_start(ifp); @@ -2213,7 +2216,7 @@ ok: stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; else stored_lft = 0; - if (!update_lft && stored_lft) { + if (!update_lft && !create && stored_lft) { if (valid_lft > MIN_VALID_LIFETIME || valid_lft > stored_lft) update_lft = 1; @@ -2459,15 +2462,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p prefered_lft = timeout; } - ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags); + ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags, + valid_lft, prefered_lft); if (!IS_ERR(ifp)) { - spin_lock_bh(&ifp->lock); - ifp->valid_lft = valid_lft; - ifp->prefered_lft = prefered_lft; - ifp->tstamp = jiffies; - spin_unlock_bh(&ifp->lock); - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, expires, flags); /* @@ -2559,7 +2557,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, { struct inet6_ifaddr *ifp; - ifp = ipv6_add_addr(idev, addr, NULL, plen, scope, IFA_F_PERMANENT); + ifp = ipv6_add_addr(idev, addr, NULL, plen, + scope, IFA_F_PERMANENT, 0, 0); if (!IS_ERR(ifp)) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; @@ -2685,7 +2684,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr #endif - ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags); + ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0); if (!IS_ERR(ifp)) { addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); addrconf_dad_start(ifp); -- cgit v0.10.2 From 0508ad646836007e6e6b62331eee7356844eac3d Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 1 Aug 2013 19:55:00 +0300 Subject: net/mlx4_core: Don't give VFs MAC addresses which are derived from the PF MAC If the user has not assigned a MAC address to a VM, then don't give it MAC which is based on the PF one. The current derivation scheme is wrong and leads to VM MAC collisions when the number of cards/hypervisors becomes big enough. Instead, just give it zeros and let them figure out what to do with that. Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 8873d68..6fc6dab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_CMD_NATIVE); if (!err && dev->caps.function != slave) { - /* if config MAC in DB use it */ - if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac) - def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; - else { - /* set slave default_mac address */ - MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET); - def_mac += slave << 8; - priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac; - } - + def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); /* get port type - currently only eth is enabled */ -- cgit v0.10.2 From b30513202c6c14120f70b2e9aa1e97d47bbc2313 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 1 Aug 2013 19:55:01 +0300 Subject: net/mlx4_core: VFs must ignore the enable_64b_cqe_eqe module param Slaves get the 64B CQE/EQE state from QUERY_HCA, not from the module parameter. If the parameter is set to zero, the slave outputs an incorrect/irrelevant warning message that 64B CQEs/EQEs are supported but not enabled (even if the hypervisor has enabled 64B CQEs/EQEs). Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index e85af92..36be320 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0; - if (!enable_64b_cqe_eqe) { + if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) { if (dev_cap->flags & (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) { mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n"); -- cgit v0.10.2 From dfcefb0be1231982784df2152213103ad33c1cfd Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 1 Aug 2013 11:10:24 +0800 Subject: net: fix a compile error when CONFIG_NET_LL_RX_POLL is not set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_NET_LL_RX_POLL is not set, I got: net/socket.c: In function ‘sock_poll’: net/socket.c:1165:4: error: implicit declaration of function ‘sk_busy_loop’ [-Werror=implicit-function-declaration] Fix this by adding a nop when !CONFIG_NET_LL_RX_POLL. Cc: Eliezer Tamir Cc: David S. Miller Signed-off-by: Cong Wang Signed-off-by: David S. Miller diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h index a14339c..6cd8848 100644 --- a/include/net/busy_poll.h +++ b/include/net/busy_poll.h @@ -181,5 +181,10 @@ static inline bool busy_loop_timeout(unsigned long end_time) return true; } +static inline bool sk_busy_loop(struct sock *sk, int nonblock) +{ + return false; +} + #endif /* CONFIG_NET_LL_RX_POLL */ #endif /* _LINUX_NET_BUSY_POLL_H */ -- cgit v0.10.2 From e0d1095ae3405404d247afb00233ef837d58da83 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 1 Aug 2013 11:10:25 +0800 Subject: net: rename CONFIG_NET_LL_RX_POLL to CONFIG_NET_RX_BUSY_POLL Eliezer renames several *ll_poll to *busy_poll, but forgets CONFIG_NET_LL_RX_POLL, so in case of confusion, rename it too. Cc: Eliezer Tamir Cc: David S. Miller Signed-off-by: Cong Wang Signed-off-by: David S. Miller diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt index 1c15043..d569f2a 100644 --- a/Documentation/sysctl/net.txt +++ b/Documentation/sysctl/net.txt @@ -52,7 +52,7 @@ Default: 64 busy_read ---------------- -Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL) +Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL) Approximate time in us to busy loop waiting for packets on the device queue. This sets the default value of the SO_BUSY_POLL socket option. Can be set or overridden per socket by setting socket option SO_BUSY_POLL, @@ -63,7 +63,7 @@ Default: 0 (off) busy_poll ---------------- -Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL) +Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL) Approximate time in us to busy loop waiting for events. Recommended value depends on the number of sockets you poll on. For several sockets 50, for several hundreds 100. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index dedbd76..d80e34b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -486,7 +486,7 @@ struct bnx2x_fastpath { struct napi_struct napi; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define BNX2X_FP_STATE_IDLE 0 #define BNX2X_FP_STATE_NAPI (1 << 0) /* NAPI owns this FP */ @@ -498,7 +498,7 @@ struct bnx2x_fastpath { #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD) /* protect state */ spinlock_t lock; -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ union host_hc_status_block status_blk; /* chip independent shortcuts into sb structure */ @@ -572,7 +572,7 @@ struct bnx2x_fastpath { #define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index])) #define bnx2x_fp_qstats(bp, fp) (&((bp)->fp_stats[(fp)->index].eth_q_stats)) -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp) { spin_lock_init(&fp->lock); @@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /* Use 2500 as a mini-jumbo MTU for FCoE */ #define BNX2X_FCOE_MINI_JUMBO_MTU 2500 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index ee350bd..f2d1ff1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3117,7 +3117,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget) return work_done; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ int bnx2x_low_latency_recv(struct napi_struct *napi) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e5da078..e06186c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12026,7 +12026,7 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = bnx2x_low_latency_recv, #endif }; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 7be725c..a6494e5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -54,7 +54,7 @@ #include -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL #define LL_EXTENDED_STATS #endif /* common prefix used by pr_<> macros */ @@ -366,7 +366,7 @@ struct ixgbe_q_vector { struct rcu_head rcu; /* to avoid race with update stats on free */ char name[IFNAMSIZ + 9]; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define IXGBE_QV_STATE_IDLE 0 #define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */ @@ -377,12 +377,12 @@ struct ixgbe_q_vector { #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD) #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD) spinlock_t lock; -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /* for dynamic allocation of rings associated with this q_vector */ struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp; }; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector) { @@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector) WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED)); return q_vector->state & IXGBE_QV_USER_PEND; } -#else /* CONFIG_NET_LL_RX_POLL */ +#else /* CONFIG_NET_RX_BUSY_POLL */ static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector) { } @@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #ifdef CONFIG_IXGBE_HWMON diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index bad8f14..be4b1fb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1998,7 +1998,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, return total_rx_packets; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ static int ixgbe_low_latency_recv(struct napi_struct *napi) { @@ -2030,7 +2030,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi) return found; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ /** * ixgbe_configure_msix - Configure MSI-X hardware @@ -7227,7 +7227,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ixgbe_netpoll, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = ixgbe_low_latency_recv, #endif #ifdef IXGBE_FCOE diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 727874f..a28cd80 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset) case ETH_SS_STATS: return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) + (priv->tx_ring_num * 2) + -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL (priv->rx_ring_num * 5); #else (priv->rx_ring_num * 2); @@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, for (i = 0; i < priv->rx_ring_num; i++) { data[index++] = priv->rx_ring[i].packets; data[index++] = priv->rx_ring[i].bytes; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL data[index++] = priv->rx_ring[i].yields; data[index++] = priv->rx_ring[i].misses; data[index++] = priv->rx_ring[i].cleaned; @@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev, "rx%d_packets", i); sprintf(data + (index++) * ETH_GSTRING_LEN, "rx%d_bytes", i); -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL sprintf(data + (index++) * ETH_GSTRING_LEN, "rx%d_napi_yield", i); sprintf(data + (index++) * ETH_GSTRING_LEN, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 5eac871..fa37b7a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up) return 0; } -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL /* must be called with local_bh_disable()d */ static int mlx4_en_low_latency_recv(struct napi_struct *napi) { @@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi) return done; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #ifdef CONFIG_RFS_ACCEL @@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = mlx4_en_low_latency_recv, #endif }; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 35fb60e..5e0aa56 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -292,7 +292,7 @@ struct mlx4_en_rx_ring { void *rx_info; unsigned long bytes; unsigned long packets; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned long yields; unsigned long misses; unsigned long cleaned; @@ -318,7 +318,7 @@ struct mlx4_en_cq { struct mlx4_cqe *buf; #define MLX4_EN_OPCODE_ERROR 0x1e -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int state; #define MLX4_EN_CQ_STATE_IDLE 0 #define MLX4_EN_CQ_STATE_NAPI 1 /* NAPI owns this CQ */ @@ -329,7 +329,7 @@ struct mlx4_en_cq { #define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD) #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD) spinlock_t poll_lock; /* protects from LLS/napi conflicts */ -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ }; struct mlx4_en_port_profile { @@ -580,7 +580,7 @@ struct mlx4_mac_entry { struct rcu_head rcu; }; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq) { spin_lock_init(&cq->poll_lock); @@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) { return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0741a1e..9a41568 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -973,7 +973,7 @@ struct net_device_ops { gfp_t gfp); void (*ndo_netpoll_cleanup)(struct net_device *dev); #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL int (*ndo_busy_poll)(struct napi_struct *dev); #endif int (*ndo_set_vf_mac)(struct net_device *dev, diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5afefa0..3b71a4e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -501,7 +501,7 @@ struct sk_buff { /* 7/9 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); -#if defined CONFIG_NET_DMA || defined CONFIG_NET_LL_RX_POLL +#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL union { unsigned int napi_id; dma_cookie_t dma_cookie; diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h index 6cd8848..f18b919 100644 --- a/include/net/busy_poll.h +++ b/include/net/busy_poll.h @@ -27,7 +27,7 @@ #include #include -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL struct napi_struct; extern unsigned int sysctl_net_busy_read __read_mostly; @@ -146,7 +146,7 @@ static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb) sk->sk_napi_id = skb->napi_id; } -#else /* CONFIG_NET_LL_RX_POLL */ +#else /* CONFIG_NET_RX_BUSY_POLL */ static inline unsigned long net_busy_loop_on(void) { return 0; @@ -186,5 +186,5 @@ static inline bool sk_busy_loop(struct sock *sk, int nonblock) return false; } -#endif /* CONFIG_NET_LL_RX_POLL */ +#endif /* CONFIG_NET_RX_BUSY_POLL */ #endif /* _LINUX_NET_BUSY_POLL_H */ diff --git a/include/net/sock.h b/include/net/sock.h index 95a5a2c..31d5cfb 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -327,7 +327,7 @@ struct sock { #ifdef CONFIG_RPS __u32 sk_rxhash; #endif -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sk_napi_id; unsigned int sk_ll_usec; #endif diff --git a/net/Kconfig b/net/Kconfig index 3770249..2b40660 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -244,7 +244,7 @@ config NETPRIO_CGROUP Cgroup subsystem for use in assigning processes to network priorities on a per-interface basis -config NET_LL_RX_POLL +config NET_RX_BUSY_POLL boolean default y diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3df4d4c..2c3d0f5 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -740,7 +740,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) skb_copy_secmark(new, old); -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL new->napi_id = old->napi_id; #endif } diff --git a/net/core/sock.c b/net/core/sock.c index 548d716..2c097c5 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -900,7 +900,7 @@ set_rcvbuf: sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool); break; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL case SO_BUSY_POLL: /* allow unprivileged users to decrease the value */ if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN)) @@ -1170,7 +1170,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE); break; -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL case SO_BUSY_POLL: v.val = sk->sk_ll_usec; break; @@ -2292,7 +2292,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp = ktime_set(-1L, 0); -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL sk->sk_napi_id = 0; sk->sk_ll_usec = sysctl_net_busy_read; #endif diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 6609686..b59b680 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -298,7 +298,7 @@ static struct ctl_table net_core_table[] = { .proc_handler = flow_limit_table_len_sysctl }, #endif /* CONFIG_NET_FLOW_LIMIT */ -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL { .procname = "busy_poll", .data = &sysctl_net_busy_poll, diff --git a/net/socket.c b/net/socket.c index 829b460..b2d7c62 100644 --- a/net/socket.c +++ b/net/socket.c @@ -106,7 +106,7 @@ #include #include -#ifdef CONFIG_NET_LL_RX_POLL +#ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; unsigned int sysctl_net_busy_poll __read_mostly; #endif -- cgit v0.10.2 From c756891a4e1c08c43780e17aca1d2b849ef31d1a Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Thu, 1 Aug 2013 08:29:18 -0400 Subject: tipc: fix oops when creating server socket fails When creation of TIPC internal server socket fails, we get an oops with the following dump: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: [] tipc_close_conn+0x59/0xb0 [tipc] PGD 13719067 PUD 12008067 PMD 0 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC Modules linked in: tipc(+) CPU: 4 PID: 4340 Comm: insmod Not tainted 3.10.0+ #1 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007 task: ffff880014360000 ti: ffff88001374c000 task.ti: ffff88001374c000 RIP: 0010:[] [] tipc_close_conn+0x59/0xb0 [tipc] RSP: 0018:ffff88001374dc98 EFLAGS: 00010292 RAX: 0000000000000000 RBX: ffff880012ac09d8 RCX: 0000000000000000 RDX: 0000000000000046 RSI: 0000000000000001 RDI: ffff880014360000 RBP: ffff88001374dcb8 R08: 0000000000000001 R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffa0016fa0 R13: ffffffffa0017010 R14: ffffffffa0017010 R15: ffff880012ac09d8 FS: 0000000000000000(0000) GS:ffff880016600000(0063) knlGS:00000000f76668d0 CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b CR2: 0000000000000020 CR3: 0000000012227000 CR4: 00000000000006e0 Stack: ffff88001374dcb8 ffffffffa0016fa0 0000000000000000 0000000000000001 ffff88001374dcf8 ffffffffa0012922 ffff88001374dce8 00000000ffffffea ffffffffa0017100 0000000000000000 ffff8800134241a8 ffffffffa0017150 Call Trace: [] tipc_server_stop+0xa2/0x1b0 [tipc] [] tipc_subscr_stop+0x15/0x20 [tipc] [] tipc_core_stop+0x1d/0x33 [tipc] [] tipc_init+0xd4/0xf8 [tipc] [] ? 0xffffffffa001efff [] do_one_initcall+0x3f/0x150 [] ? __blocking_notifier_call_chain+0x7d/0xd0 [] load_module+0x11aa/0x19c0 [] ? show_initstate+0x50/0x50 [] ? retint_restore_args+0xe/0xe [] SyS_init_module+0xd9/0x110 [] sysenter_dispatch+0x7/0x1f Code: 6c 24 70 4c 89 ef e8 b7 04 8f e1 8b 73 04 4c 89 e7 e8 7c 9e 32 e1 41 83 ac 24 b8 00 00 00 01 4c 89 ef e8 eb 0a 8f e1 48 8b 43 08 <4c> 8b 68 20 4d 8d a5 48 03 00 00 4c 89 e7 e8 04 05 8f e1 4c 89 RIP [] tipc_close_conn+0x59/0xb0 [tipc] RSP CR2: 0000000000000020 ---[ end trace b02321f40e4269a3 ]--- We have the following call chain: tipc_core_start() ret = tipc_subscr_start() ret = tipc_server_start(){ server->enabled = 1; ret = tipc_open_listening_sock() } I.e., the server->enabled flag is unconditionally set to 1, whatever the return value of tipc_open_listening_sock(). This causes a crash when tipc_core_start() tries to clean up resources after a failed initialization: if (ret == failed) tipc_subscr_stop() tipc_server_stop(){ if (server->enabled) tipc_close_conn(){ NULL reference of con->sock-sk OOPS! } } To avoid this, tipc_server_start() should only set server->enabled to 1 in case of a succesful socket creation. In case of failure, it should release all allocated resources before returning. Problem introduced in commit c5fa7b3cf3cb22e4ac60485fc2dc187fe012910f ("tipc: introduce new TIPC server infrastructure") in v3.11-rc1. Note that it won't be seen often; it takes a module load under memory constrained conditions in order to trigger the failure condition. Signed-off-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: Paul Gortmaker Signed-off-by: David S. Miller diff --git a/net/tipc/server.c b/net/tipc/server.c index 19da5ab..fd3fa57 100644 --- a/net/tipc/server.c +++ b/net/tipc/server.c @@ -355,8 +355,12 @@ static int tipc_open_listening_sock(struct tipc_server *s) return PTR_ERR(con); sock = tipc_create_listen_sock(con); - if (!sock) + if (!sock) { + idr_remove(&s->conn_idr, con->conid); + s->idr_in_use--; + kfree(con); return -EINVAL; + } tipc_register_callbacks(sock, con); return 0; @@ -563,9 +567,14 @@ int tipc_server_start(struct tipc_server *s) kmem_cache_destroy(s->rcvbuf_cache); return ret; } + ret = tipc_open_listening_sock(s); + if (ret < 0) { + tipc_work_stop(s); + kmem_cache_destroy(s->rcvbuf_cache); + return ret; + } s->enabled = 1; - - return tipc_open_listening_sock(s); + return ret; } void tipc_server_stop(struct tipc_server *s) -- cgit v0.10.2 From 266e83474c98e9f18d31f4837cfe05819a660d32 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 1 Aug 2013 13:43:19 +0300 Subject: macvlan: better mode validation macvlan passthrough mode is special: it's not possible to switch to or from it through a netlink command. But if you try, the command will succeed, which is confusing. Validate input and return error to user. Cc: Sridhar Samudrala Cc: "David S. Miller" Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 18373b6..13937f9 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -863,6 +863,18 @@ static int macvlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); + enum macvlan_mode mode; + bool set_mode = false; + + /* Validate mode, but don't set yet: setting flags may fail. */ + if (data && data[IFLA_MACVLAN_MODE]) { + set_mode = true; + mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + /* Passthrough mode can't be set or cleared dynamically */ + if ((mode == MACVLAN_MODE_PASSTHRU) != + (vlan->mode == MACVLAN_MODE_PASSTHRU)) + return -EINVAL; + } if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); @@ -879,8 +891,8 @@ static int macvlan_changelink(struct net_device *dev, } vlan->flags = flags; } - if (data && data[IFLA_MACVLAN_MODE]) - vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (set_mode) + vlan->mode = mode; return 0; } -- cgit v0.10.2 From 787381415cf967c5d6d1d7c5b5bd893376945edd Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 1 Aug 2013 13:50:10 +0300 Subject: macvlan: handle set_promiscuity failures It's quite unlikely that dev_set_promiscuity will fail, but worth checking just in case. Cc: "David S. Miller" Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 13937f9..d0f9c2f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev) int err; if (vlan->port->passthru) { - if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) - dev_set_promiscuity(lowerdev, 1); + if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) { + err = dev_set_promiscuity(lowerdev, 1); + if (err < 0) + goto out; + } goto hash_add; } -- cgit v0.10.2 From 697aebab78a88c6b164cfb74d19b86817d2ccd82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Aug 2013 08:38:27 +0200 Subject: ALSA: hda - Fix missing fixup for Mac Mini with STAC9221 A fixup for Apple Mac Mini was lost during the adaption to the generic parser because the fallback for the generic ID 8384:7680 was dropped, and it resulted in the silence output (and maybe other problems). Unfortunately, just adding the missing subsystem ID wasn't enough, in this case. The subsystem ID of this machine is 0000:0100 (what Apple thought...?), and since snd_hda_pick_fixup() doesn't take the vendor id zero into account, the driver ignored this entry. Now it's fixed to regard the vendor id zero as a valid value. Reported-and-tested-by: Linus Torvalds Cc: [v3.9+] Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7c11d46..48a9d00 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -860,7 +860,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } if (id < 0 && quirk) { - for (q = quirk; q->subvendor; q++) { + for (q = quirk; q->subvendor || q->subdevice; q++) { unsigned int vendorid = q->subdevice | (q->subvendor << 16); unsigned int mask = 0xffff0000 | q->subdevice_mask; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 92b9b43..6d1924c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2819,6 +2819,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = { /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { + SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3), SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2), -- cgit v0.10.2 From cbd375567f7e4811b1c721f75ec519828ac6583f Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 1 Aug 2013 22:32:07 -0700 Subject: htb: fix sign extension bug When userspace passes a large priority value the assignment of the unsigned value hopt->prio to signed int cl->prio causes cl->prio to become negative and the comparison is with TC_HTB_NUMPRIO is always false. The result is that HTB crashes by referencing outside the array when processing packets. With this patch the large value wraps around like other values outside the normal range. See: https://bugzilla.kernel.org/show_bug.cgi?id=60669 Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index c2124ea..45e7515 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -100,7 +100,7 @@ struct htb_class { struct psched_ratecfg ceil; s64 buffer, cbuffer;/* token bucket depth/rate */ s64 mbuffer; /* max wait time */ - int prio; /* these two are used only by leaves... */ + u32 prio; /* these two are used only by leaves... */ int quantum; /* but stored for parent-to-leaf return */ struct tcf_proto *filter_list; /* class attached filters */ -- cgit v0.10.2 From 7069f982b9099133b44e3cecbdd0192d81590bec Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 2 Aug 2013 10:44:10 +0300 Subject: net: ethernet: cpsw: drop IRQF_DISABLED IRQF_DISABLED is a no-op by now and should be removed. Signed-off-by: Felipe Balbi Acked-by: Mugunthan V N Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 05a1674..22a7a43 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1867,7 +1867,7 @@ static int cpsw_probe(struct platform_device *pdev) while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, cpsw_interrupt, IRQF_DISABLED, + if (request_irq(i, cpsw_interrupt, 0, dev_name(&pdev->dev), priv)) { dev_err(priv->dev, "error attaching irq\n"); goto clean_ale_ret; -- cgit v0.10.2 From 9bb8eeb554795e6fac7cacf7af44bf413e75c9b9 Mon Sep 17 00:00:00 2001 From: Lekensteyn Date: Fri, 2 Aug 2013 10:36:55 +0200 Subject: r8169: remove "PHY reset until link up" log spam This message was added in commit a7154cb8 (June 2004, [PATCH] r8169: link handling and phy reset rework) and is printed every ten seconds when no cable is connected and runtime power management is disabled. (Before that commit, "Reset RTL8169s PHY" would be printed instead.) Signed-off-by: Peter Wu Acked-by: Francois Romieu Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 880015c..b5eb419 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -3689,7 +3689,7 @@ static void rtl_phy_work(struct rtl8169_private *tp) if (tp->link_ok(ioaddr)) return; - netif_warn(tp, link, tp->dev, "PHY reset until link up\n"); + netif_dbg(tp, link, tp->dev, "PHY reset until link up\n"); tp->phy_reset_enable(tp); -- cgit v0.10.2 From 446266b0c742a2c9ee8f0dce759a0117bce58a86 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 2 Aug 2013 11:32:43 +0200 Subject: net: rtm_to_ifaddr: free ifa if ifa_cacheinfo processing fails Commit 5c766d642 ("ipv4: introduce address lifetime") leaves the ifa resource that was allocated via inet_alloc_ifa() unfreed when returning the function with -EINVAL. Thus, free it first via inet_free_ifa(). Signed-off-by: Daniel Borkmann Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 8d48c39..34ca6d5 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -772,7 +772,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, ci = nla_data(tb[IFA_CACHEINFO]); if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) { err = -EINVAL; - goto errout; + goto errout_free; } *pvalid_lft = ci->ifa_valid; *pprefered_lft = ci->ifa_prefered; @@ -780,6 +780,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, return ifa; +errout_free: + inet_free_ifa(ifa); errout: return ERR_PTR(err); } -- cgit v0.10.2 From 3508ea333ed5414561af4c818b3b80c0acca1845 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Fri, 2 Aug 2013 13:50:54 +0400 Subject: sis900: Fix the tx queue timeout issue [ 198.720048] ------------[ cut here ]------------ [ 198.720108] WARNING: CPU: 0 PID: 0 at net/sched/sch_generic.c:255 dev_watchdog+0x229/0x240() [ 198.720118] NETDEV WATCHDOG: eth0 (sis900): transmit queue 0 timed out [ 198.720125] Modules linked in: bridge stp llc dmfe sundance 3c59x sis900 mii [ 198.720159] CPU: 0 PID: 0 Comm: swapper Not tainted 3.11.0-rc3+ #12 [ 198.720167] Hardware name: System Manufacturer System Name/TUSI-M, BIOS ASUS TUSI-M ACPI BIOS Revision 1013 Beta 001 12/14/2001 [ 198.720175] 000000ff c13fa6b9 c169ddcc c12208d6 c169ddf8 c1031e4d c1664a84 c169de24 [ 198.720197] 00000000 c165f5ea 000000ff c13fa6b9 00000001 000000ff c1664a84 c169de10 [ 198.720217] c1031f13 00000009 c169de08 c1664a84 c169de24 c169de50 c13fa6b9 c165f5ea [ 198.720240] Call Trace: [ 198.720257] [] ? dev_watchdog+0x229/0x240 [ 198.720274] [] dump_stack+0x16/0x20 [ 198.720306] [] warn_slowpath_common+0x7d/0xa0 [ 198.720318] [] ? dev_watchdog+0x229/0x240 [ 198.720330] [] warn_slowpath_fmt+0x33/0x40 [ 198.720342] [] dev_watchdog+0x229/0x240 [ 198.720357] [] call_timer_fn+0x78/0x150 [ 198.720369] [] ? internal_add_timer+0x40/0x40 [ 198.720381] [] ? dev_init_scheduler+0xa0/0xa0 [ 198.720392] [] run_timer_softirq+0x10f/0x200 [ 198.720412] [] ? __do_softirq+0x6f/0x210 [ 198.720424] [] ? dev_init_scheduler+0xa0/0xa0 [ 198.720435] [] __do_softirq+0xb8/0x210 [ 198.720467] [] ? _raw_spin_unlock+0x22/0x30 [ 198.720484] [] ? handle_irq+0x25/0xd0 [ 198.720496] [] irq_exit+0x9c/0xb0 [ 198.720508] [] do_IRQ+0x47/0x94 [ 198.720534] [] ? hrtimer_start+0x28/0x30 [ 198.720564] [] common_interrupt+0x31/0x38 [ 198.720589] [] ? default_idle+0x22/0xa0 [ 198.720600] [] arch_cpu_idle+0x17/0x30 [ 198.720631] [] cpu_startup_entry+0xcd/0x180 [ 198.720643] [] rest_init+0xaa/0xb0 [ 198.720654] [] ? reciprocal_value+0x50/0x50 [ 198.720668] [] ? repair_env_string+0x60/0x60 [ 198.720679] [] start_kernel+0x29a/0x350 [ 198.720690] [] ? repair_env_string+0x60/0x60 [ 198.720721] [] i386_start_kernel+0x39/0xa0 [ 198.720729] ---[ end trace 81e0a6266f5c73a8 ]--- [ 198.720740] eth0: Transmit timeout, status 00000204 00000000 timer routine checks the link status and if it's up calls netif_carrier_on() allowing upper layer to start the tx queue even if the auto-negotiation process is not finished. Also remove ugly auto-negotiation check from the sis900_start_xmit() CC: Duan Fugang CC: Ben Hutchings Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index eb4aea3..f5d7ad7 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -1318,7 +1318,7 @@ static void sis900_timer(unsigned long data) if (duplex){ sis900_set_mode(sis_priv, speed, duplex); sis630_set_eq(net_dev, sis_priv->chipset_rev); - netif_start_queue(net_dev); + netif_carrier_on(net_dev); } sis_priv->timer.expires = jiffies + HZ; @@ -1336,10 +1336,8 @@ static void sis900_timer(unsigned long data) status = sis900_default_phy(net_dev); mii_phy = sis_priv->mii; - if (status & MII_STAT_LINK){ + if (status & MII_STAT_LINK) sis900_check_mode(net_dev, mii_phy); - netif_carrier_on(net_dev); - } } else { /* Link ON -> OFF */ if (!(status & MII_STAT_LINK)){ @@ -1612,12 +1610,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) unsigned int index_cur_tx, index_dirty_tx; unsigned int count_dirty_tx; - /* Don't transmit data before the complete of auto-negotiation */ - if(!sis_priv->autong_complete){ - netif_stop_queue(net_dev); - return NETDEV_TX_BUSY; - } - spin_lock_irqsave(&sis_priv->lock, flags); /* Calculate the next Tx descriptor entry. */ -- cgit v0.10.2 From 5f671d6b4ec3e6d66c2a868738af2cdea09e7509 Mon Sep 17 00:00:00 2001 From: Roman Gushchin Date: Fri, 2 Aug 2013 18:36:40 +0400 Subject: net: check net.core.somaxconn sysctl values It's possible to assign an invalid value to the net.core.somaxconn sysctl variable, because there is no checks at all. The sk_max_ack_backlog field of the sock structure is defined as unsigned short. Therefore, the backlog argument in inet_listen() shouldn't exceed USHRT_MAX. The backlog argument in the listen() syscall is truncated to the somaxconn value. So, the somaxconn value shouldn't exceed 65535 (USHRT_MAX). Also, negative values of somaxconn are meaningless. before: $ sysctl -w net.core.somaxconn=256 net.core.somaxconn = 256 $ sysctl -w net.core.somaxconn=65536 net.core.somaxconn = 65536 $ sysctl -w net.core.somaxconn=-100 net.core.somaxconn = -100 after: $ sysctl -w net.core.somaxconn=256 net.core.somaxconn = 256 $ sysctl -w net.core.somaxconn=65536 error: "Invalid argument" setting key "net.core.somaxconn" $ sysctl -w net.core.somaxconn=-100 error: "Invalid argument" setting key "net.core.somaxconn" Based on a prior patch from Changli Gao. Signed-off-by: Roman Gushchin Reported-by: Changli Gao Suggested-by: Eric Dumazet Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index b59b680..31107ab 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -21,7 +21,9 @@ #include #include +static int zero = 0; static int one = 1; +static int ushort_max = USHRT_MAX; #ifdef CONFIG_RPS static int rps_sock_flow_sysctl(struct ctl_table *table, int write, @@ -339,7 +341,9 @@ static struct ctl_table netns_core_table[] = { .data = &init_net.core.sysctl_somaxconn, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec + .extra1 = &zero, + .extra2 = &ushort_max, + .proc_handler = proc_dointvec_minmax }, { } }; -- cgit v0.10.2 From 6a8b7f0c85f1f42eb8b6e68ef3d5ba8020d8e272 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Fri, 2 Aug 2013 14:45:08 -0400 Subject: netlabel: use domain based selectors when address based selectors are not available NetLabel has the ability to selectively assign network security labels to outbound traffic based on either the LSM's "domain" (different for each LSM), the network destination, or a combination of both. Depending on the type of traffic, local or forwarded, and the type of traffic selector, domain or address based, different hooks are used to label the traffic; the goal being minimal overhead. Unfortunately, there is a bug such that a system using NetLabel domain based traffic selectors does not correctly label outbound local traffic that is not assigned to a socket. The issue is that in these cases the associated NetLabel hook only looks at the address based selectors and not the domain based selectors. This patch corrects this by checking both the domain and address based selectors so that the correct labeling is applied, regardless of the configuration type. In order to acomplish this fix, this patch also simplifies some of the NetLabel domainhash structures to use a more common outbound traffic mapping type: struct netlbl_dommap_def. This simplifies some of the code in this patch and paves the way for further simplifications in the future. Signed-off-by: Paul Moore Signed-off-by: David S. Miller diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index c15042f..a110064 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -691,8 +691,8 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg) { struct netlbl_domhsh_walk_arg *cb_arg = arg; - if (entry->type == NETLBL_NLTYPE_CIPSOV4 && - entry->type_def.cipsov4->doi == cb_arg->doi) + if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 && + entry->def.cipso->doi == cb_arg->doi) return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info); return 0; diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 6bb1d42..85d842e 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -84,15 +84,15 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry) #endif /* IPv6 */ ptr = container_of(entry, struct netlbl_dom_map, rcu); - if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) { + if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) { netlbl_af4list_foreach_safe(iter4, tmp4, - &ptr->type_def.addrsel->list4) { + &ptr->def.addrsel->list4) { netlbl_af4list_remove_entry(iter4); kfree(netlbl_domhsh_addr4_entry(iter4)); } #if IS_ENABLED(CONFIG_IPV6) netlbl_af6list_foreach_safe(iter6, tmp6, - &ptr->type_def.addrsel->list6) { + &ptr->def.addrsel->list6) { netlbl_af6list_remove_entry(iter6); kfree(netlbl_domhsh_addr6_entry(iter6)); } @@ -213,21 +213,21 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, if (addr4 != NULL) { struct netlbl_domaddr4_map *map4; map4 = netlbl_domhsh_addr4_entry(addr4); - type = map4->type; - cipsov4 = map4->type_def.cipsov4; + type = map4->def.type; + cipsov4 = map4->def.cipso; netlbl_af4list_audit_addr(audit_buf, 0, NULL, addr4->addr, addr4->mask); #if IS_ENABLED(CONFIG_IPV6) } else if (addr6 != NULL) { struct netlbl_domaddr6_map *map6; map6 = netlbl_domhsh_addr6_entry(addr6); - type = map6->type; + type = map6->def.type; netlbl_af6list_audit_addr(audit_buf, 0, NULL, &addr6->addr, &addr6->mask); #endif /* IPv6 */ } else { - type = entry->type; - cipsov4 = entry->type_def.cipsov4; + type = entry->def.type; + cipsov4 = entry->def.cipso; } switch (type) { case NETLBL_NLTYPE_UNLABELED: @@ -265,26 +265,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry) if (entry == NULL) return -EINVAL; - switch (entry->type) { + switch (entry->def.type) { case NETLBL_NLTYPE_UNLABELED: - if (entry->type_def.cipsov4 != NULL || - entry->type_def.addrsel != NULL) + if (entry->def.cipso != NULL || entry->def.addrsel != NULL) return -EINVAL; break; case NETLBL_NLTYPE_CIPSOV4: - if (entry->type_def.cipsov4 == NULL) + if (entry->def.cipso == NULL) return -EINVAL; break; case NETLBL_NLTYPE_ADDRSELECT: - netlbl_af4list_foreach(iter4, &entry->type_def.addrsel->list4) { + netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) { map4 = netlbl_domhsh_addr4_entry(iter4); - switch (map4->type) { + switch (map4->def.type) { case NETLBL_NLTYPE_UNLABELED: - if (map4->type_def.cipsov4 != NULL) + if (map4->def.cipso != NULL) return -EINVAL; break; case NETLBL_NLTYPE_CIPSOV4: - if (map4->type_def.cipsov4 == NULL) + if (map4->def.cipso == NULL) return -EINVAL; break; default: @@ -292,9 +291,9 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry) } } #if IS_ENABLED(CONFIG_IPV6) - netlbl_af6list_foreach(iter6, &entry->type_def.addrsel->list6) { + netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) { map6 = netlbl_domhsh_addr6_entry(iter6); - switch (map6->type) { + switch (map6->def.type) { case NETLBL_NLTYPE_UNLABELED: break; default: @@ -402,32 +401,31 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, rcu_assign_pointer(netlbl_domhsh_def, entry); } - if (entry->type == NETLBL_NLTYPE_ADDRSELECT) { + if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) { netlbl_af4list_foreach_rcu(iter4, - &entry->type_def.addrsel->list4) + &entry->def.addrsel->list4) netlbl_domhsh_audit_add(entry, iter4, NULL, ret_val, audit_info); #if IS_ENABLED(CONFIG_IPV6) netlbl_af6list_foreach_rcu(iter6, - &entry->type_def.addrsel->list6) + &entry->def.addrsel->list6) netlbl_domhsh_audit_add(entry, NULL, iter6, ret_val, audit_info); #endif /* IPv6 */ } else netlbl_domhsh_audit_add(entry, NULL, NULL, ret_val, audit_info); - } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT && - entry->type == NETLBL_NLTYPE_ADDRSELECT) { + } else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT && + entry->def.type == NETLBL_NLTYPE_ADDRSELECT) { struct list_head *old_list4; struct list_head *old_list6; - old_list4 = &entry_old->type_def.addrsel->list4; - old_list6 = &entry_old->type_def.addrsel->list6; + old_list4 = &entry_old->def.addrsel->list4; + old_list6 = &entry_old->def.addrsel->list6; /* we only allow the addition of address selectors if all of * the selectors do not exist in the existing domain map */ - netlbl_af4list_foreach_rcu(iter4, - &entry->type_def.addrsel->list4) + netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) if (netlbl_af4list_search_exact(iter4->addr, iter4->mask, old_list4)) { @@ -435,8 +433,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, goto add_return; } #if IS_ENABLED(CONFIG_IPV6) - netlbl_af6list_foreach_rcu(iter6, - &entry->type_def.addrsel->list6) + netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) if (netlbl_af6list_search_exact(&iter6->addr, &iter6->mask, old_list6)) { @@ -446,7 +443,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, #endif /* IPv6 */ netlbl_af4list_foreach_safe(iter4, tmp4, - &entry->type_def.addrsel->list4) { + &entry->def.addrsel->list4) { netlbl_af4list_remove_entry(iter4); iter4->valid = 1; ret_val = netlbl_af4list_add(iter4, old_list4); @@ -457,7 +454,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, } #if IS_ENABLED(CONFIG_IPV6) netlbl_af6list_foreach_safe(iter6, tmp6, - &entry->type_def.addrsel->list6) { + &entry->def.addrsel->list6) { netlbl_af6list_remove_entry(iter6); iter6->valid = 1; ret_val = netlbl_af6list_add(iter6, old_list6); @@ -538,18 +535,18 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, struct netlbl_af4list *iter4; struct netlbl_domaddr4_map *map4; - switch (entry->type) { + switch (entry->def.type) { case NETLBL_NLTYPE_ADDRSELECT: netlbl_af4list_foreach_rcu(iter4, - &entry->type_def.addrsel->list4) { + &entry->def.addrsel->list4) { map4 = netlbl_domhsh_addr4_entry(iter4); - cipso_v4_doi_putdef(map4->type_def.cipsov4); + cipso_v4_doi_putdef(map4->def.cipso); } /* no need to check the IPv6 list since we currently * support only unlabeled protocols for IPv6 */ break; case NETLBL_NLTYPE_CIPSOV4: - cipso_v4_doi_putdef(entry->type_def.cipsov4); + cipso_v4_doi_putdef(entry->def.cipso); break; } call_rcu(&entry->rcu, netlbl_domhsh_free_entry); @@ -590,20 +587,21 @@ int netlbl_domhsh_remove_af4(const char *domain, entry_map = netlbl_domhsh_search(domain); else entry_map = netlbl_domhsh_search_def(domain); - if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT) + if (entry_map == NULL || + entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT) goto remove_af4_failure; spin_lock(&netlbl_domhsh_lock); entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr, - &entry_map->type_def.addrsel->list4); + &entry_map->def.addrsel->list4); spin_unlock(&netlbl_domhsh_lock); if (entry_addr == NULL) goto remove_af4_failure; - netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4) + netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4) goto remove_af4_single_addr; #if IS_ENABLED(CONFIG_IPV6) - netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6) + netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6) goto remove_af4_single_addr; #endif /* IPv6 */ /* the domain mapping is empty so remove it from the mapping table */ @@ -616,7 +614,7 @@ remove_af4_single_addr: * shouldn't be a problem */ synchronize_rcu(); entry = netlbl_domhsh_addr4_entry(entry_addr); - cipso_v4_doi_putdef(entry->type_def.cipsov4); + cipso_v4_doi_putdef(entry->def.cipso); kfree(entry); return 0; @@ -693,8 +691,8 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) * responsible for ensuring that rcu_read_[un]lock() is called. * */ -struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, - __be32 addr) +struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, + __be32 addr) { struct netlbl_dom_map *dom_iter; struct netlbl_af4list *addr_iter; @@ -702,15 +700,13 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, dom_iter = netlbl_domhsh_search_def(domain); if (dom_iter == NULL) return NULL; - if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) - return NULL; - addr_iter = netlbl_af4list_search(addr, - &dom_iter->type_def.addrsel->list4); + if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT) + return &dom_iter->def; + addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4); if (addr_iter == NULL) return NULL; - - return netlbl_domhsh_addr4_entry(addr_iter); + return &(netlbl_domhsh_addr4_entry(addr_iter)->def); } #if IS_ENABLED(CONFIG_IPV6) @@ -725,7 +721,7 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, * responsible for ensuring that rcu_read_[un]lock() is called. * */ -struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, +struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, const struct in6_addr *addr) { struct netlbl_dom_map *dom_iter; @@ -734,15 +730,13 @@ struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, dom_iter = netlbl_domhsh_search_def(domain); if (dom_iter == NULL) return NULL; - if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) - return NULL; - addr_iter = netlbl_af6list_search(addr, - &dom_iter->type_def.addrsel->list6); + if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT) + return &dom_iter->def; + addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6); if (addr_iter == NULL) return NULL; - - return netlbl_domhsh_addr6_entry(addr_iter); + return &(netlbl_domhsh_addr6_entry(addr_iter)->def); } #endif /* IPv6 */ diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index 90872c4..b9be0ee 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h @@ -43,37 +43,35 @@ #define NETLBL_DOMHSH_BITSIZE 7 /* Domain mapping definition structures */ +struct netlbl_domaddr_map { + struct list_head list4; + struct list_head list6; +}; +struct netlbl_dommap_def { + u32 type; + union { + struct netlbl_domaddr_map *addrsel; + struct cipso_v4_doi *cipso; + }; +}; #define netlbl_domhsh_addr4_entry(iter) \ container_of(iter, struct netlbl_domaddr4_map, list) struct netlbl_domaddr4_map { - u32 type; - union { - struct cipso_v4_doi *cipsov4; - } type_def; + struct netlbl_dommap_def def; struct netlbl_af4list list; }; #define netlbl_domhsh_addr6_entry(iter) \ container_of(iter, struct netlbl_domaddr6_map, list) struct netlbl_domaddr6_map { - u32 type; - - /* NOTE: no 'type_def' union needed at present since we don't currently - * support any IPv6 labeling protocols */ + struct netlbl_dommap_def def; struct netlbl_af6list list; }; -struct netlbl_domaddr_map { - struct list_head list4; - struct list_head list6; -}; + struct netlbl_dom_map { char *domain; - u32 type; - union { - struct cipso_v4_doi *cipsov4; - struct netlbl_domaddr_map *addrsel; - } type_def; + struct netlbl_dommap_def def; u32 valid; struct list_head list; @@ -97,16 +95,16 @@ int netlbl_domhsh_remove_af4(const char *domain, int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info); struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain); -struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, - __be32 addr); +struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain, + __be32 addr); +#if IS_ENABLED(CONFIG_IPV6) +struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain, + const struct in6_addr *addr); +#endif /* IPv6 */ + int netlbl_domhsh_walk(u32 *skip_bkt, u32 *skip_chain, int (*callback) (struct netlbl_dom_map *entry, void *arg), void *cb_arg); -#if IS_ENABLED(CONFIG_IPV6) -struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, - const struct in6_addr *addr); -#endif /* IPv6 */ - #endif diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index 7c94aed..96a458e 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -122,7 +122,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain, } if (addr == NULL && mask == NULL) - entry->type = NETLBL_NLTYPE_UNLABELED; + entry->def.type = NETLBL_NLTYPE_UNLABELED; else if (addr != NULL && mask != NULL) { addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); if (addrmap == NULL) @@ -137,7 +137,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain, map4 = kzalloc(sizeof(*map4), GFP_ATOMIC); if (map4 == NULL) goto cfg_unlbl_map_add_failure; - map4->type = NETLBL_NLTYPE_UNLABELED; + map4->def.type = NETLBL_NLTYPE_UNLABELED; map4->list.addr = addr4->s_addr & mask4->s_addr; map4->list.mask = mask4->s_addr; map4->list.valid = 1; @@ -154,7 +154,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain, map6 = kzalloc(sizeof(*map6), GFP_ATOMIC); if (map6 == NULL) goto cfg_unlbl_map_add_failure; - map6->type = NETLBL_NLTYPE_UNLABELED; + map6->def.type = NETLBL_NLTYPE_UNLABELED; map6->list.addr = *addr6; map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0]; map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1]; @@ -174,8 +174,8 @@ int netlbl_cfg_unlbl_map_add(const char *domain, break; } - entry->type_def.addrsel = addrmap; - entry->type = NETLBL_NLTYPE_ADDRSELECT; + entry->def.addrsel = addrmap; + entry->def.type = NETLBL_NLTYPE_ADDRSELECT; } else { ret_val = -EINVAL; goto cfg_unlbl_map_add_failure; @@ -355,8 +355,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, } if (addr == NULL && mask == NULL) { - entry->type_def.cipsov4 = doi_def; - entry->type = NETLBL_NLTYPE_CIPSOV4; + entry->def.cipso = doi_def; + entry->def.type = NETLBL_NLTYPE_CIPSOV4; } else if (addr != NULL && mask != NULL) { addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC); if (addrmap == NULL) @@ -367,8 +367,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC); if (addrinfo == NULL) goto out_addrinfo; - addrinfo->type_def.cipsov4 = doi_def; - addrinfo->type = NETLBL_NLTYPE_CIPSOV4; + addrinfo->def.cipso = doi_def; + addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4; addrinfo->list.addr = addr->s_addr & mask->s_addr; addrinfo->list.mask = mask->s_addr; addrinfo->list.valid = 1; @@ -376,8 +376,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi, if (ret_val != 0) goto cfg_cipsov4_map_add_failure; - entry->type_def.addrsel = addrmap; - entry->type = NETLBL_NLTYPE_ADDRSELECT; + entry->def.addrsel = addrmap; + entry->def.type = NETLBL_NLTYPE_ADDRSELECT; } else { ret_val = -EINVAL; goto out_addrmap; @@ -657,14 +657,14 @@ int netlbl_sock_setattr(struct sock *sk, } switch (family) { case AF_INET: - switch (dom_entry->type) { + switch (dom_entry->def.type) { case NETLBL_NLTYPE_ADDRSELECT: ret_val = -EDESTADDRREQ; break; case NETLBL_NLTYPE_CIPSOV4: ret_val = cipso_v4_sock_setattr(sk, - dom_entry->type_def.cipsov4, - secattr); + dom_entry->def.cipso, + secattr); break; case NETLBL_NLTYPE_UNLABELED: ret_val = 0; @@ -754,23 +754,22 @@ int netlbl_conn_setattr(struct sock *sk, { int ret_val; struct sockaddr_in *addr4; - struct netlbl_domaddr4_map *af4_entry; + struct netlbl_dommap_def *entry; rcu_read_lock(); switch (addr->sa_family) { case AF_INET: addr4 = (struct sockaddr_in *)addr; - af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, - addr4->sin_addr.s_addr); - if (af4_entry == NULL) { + entry = netlbl_domhsh_getentry_af4(secattr->domain, + addr4->sin_addr.s_addr); + if (entry == NULL) { ret_val = -ENOENT; goto conn_setattr_return; } - switch (af4_entry->type) { + switch (entry->type) { case NETLBL_NLTYPE_CIPSOV4: ret_val = cipso_v4_sock_setattr(sk, - af4_entry->type_def.cipsov4, - secattr); + entry->cipso, secattr); break; case NETLBL_NLTYPE_UNLABELED: /* just delete the protocols we support for right now @@ -812,36 +811,21 @@ int netlbl_req_setattr(struct request_sock *req, const struct netlbl_lsm_secattr *secattr) { int ret_val; - struct netlbl_dom_map *dom_entry; - struct netlbl_domaddr4_map *af4_entry; - u32 proto_type; - struct cipso_v4_doi *proto_cv4; + struct netlbl_dommap_def *entry; rcu_read_lock(); - dom_entry = netlbl_domhsh_getentry(secattr->domain); - if (dom_entry == NULL) { - ret_val = -ENOENT; - goto req_setattr_return; - } switch (req->rsk_ops->family) { case AF_INET: - if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) { - struct inet_request_sock *req_inet = inet_rsk(req); - af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, - req_inet->rmt_addr); - if (af4_entry == NULL) { - ret_val = -ENOENT; - goto req_setattr_return; - } - proto_type = af4_entry->type; - proto_cv4 = af4_entry->type_def.cipsov4; - } else { - proto_type = dom_entry->type; - proto_cv4 = dom_entry->type_def.cipsov4; + entry = netlbl_domhsh_getentry_af4(secattr->domain, + inet_rsk(req)->rmt_addr); + if (entry == NULL) { + ret_val = -ENOENT; + goto req_setattr_return; } - switch (proto_type) { + switch (entry->type) { case NETLBL_NLTYPE_CIPSOV4: - ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr); + ret_val = cipso_v4_req_setattr(req, + entry->cipso, secattr); break; case NETLBL_NLTYPE_UNLABELED: /* just delete the protocols we support for right now @@ -899,23 +883,21 @@ int netlbl_skbuff_setattr(struct sk_buff *skb, { int ret_val; struct iphdr *hdr4; - struct netlbl_domaddr4_map *af4_entry; + struct netlbl_dommap_def *entry; rcu_read_lock(); switch (family) { case AF_INET: hdr4 = ip_hdr(skb); - af4_entry = netlbl_domhsh_getentry_af4(secattr->domain, - hdr4->daddr); - if (af4_entry == NULL) { + entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr); + if (entry == NULL) { ret_val = -ENOENT; goto skbuff_setattr_return; } - switch (af4_entry->type) { + switch (entry->type) { case NETLBL_NLTYPE_CIPSOV4: - ret_val = cipso_v4_skbuff_setattr(skb, - af4_entry->type_def.cipsov4, - secattr); + ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso, + secattr); break; case NETLBL_NLTYPE_UNLABELED: /* just delete the protocols we support for right now diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index c5384ff..dd1c37d 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -104,7 +104,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, ret_val = -ENOMEM; goto add_failure; } - entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); + entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]); if (info->attrs[NLBL_MGMT_A_DOMAIN]) { size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]); entry->domain = kmalloc(tmp_size, GFP_KERNEL); @@ -116,12 +116,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size); } - /* NOTE: internally we allow/use a entry->type value of + /* NOTE: internally we allow/use a entry->def.type value of * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users * to pass that as a protocol value because we need to know the * "real" protocol */ - switch (entry->type) { + switch (entry->def.type) { case NETLBL_NLTYPE_UNLABELED: break; case NETLBL_NLTYPE_CIPSOV4: @@ -132,7 +132,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, cipsov4 = cipso_v4_doi_getdef(tmp_val); if (cipsov4 == NULL) goto add_failure; - entry->type_def.cipsov4 = cipsov4; + entry->def.cipso = cipsov4; break; default: goto add_failure; @@ -172,9 +172,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info, map->list.addr = addr->s_addr & mask->s_addr; map->list.mask = mask->s_addr; map->list.valid = 1; - map->type = entry->type; + map->def.type = entry->def.type; if (cipsov4) - map->type_def.cipsov4 = cipsov4; + map->def.cipso = cipsov4; ret_val = netlbl_af4list_add(&map->list, &addrmap->list4); if (ret_val != 0) { @@ -182,8 +182,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info, goto add_failure; } - entry->type = NETLBL_NLTYPE_ADDRSELECT; - entry->type_def.addrsel = addrmap; + entry->def.type = NETLBL_NLTYPE_ADDRSELECT; + entry->def.addrsel = addrmap; #if IS_ENABLED(CONFIG_IPV6) } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) { struct in6_addr *addr; @@ -223,7 +223,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info, map->list.addr.s6_addr32[3] &= mask->s6_addr32[3]; map->list.mask = *mask; map->list.valid = 1; - map->type = entry->type; + map->def.type = entry->def.type; ret_val = netlbl_af6list_add(&map->list, &addrmap->list6); if (ret_val != 0) { @@ -231,8 +231,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info, goto add_failure; } - entry->type = NETLBL_NLTYPE_ADDRSELECT; - entry->type_def.addrsel = addrmap; + entry->def.type = NETLBL_NLTYPE_ADDRSELECT; + entry->def.addrsel = addrmap; #endif /* IPv6 */ } @@ -281,14 +281,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, return ret_val; } - switch (entry->type) { + switch (entry->def.type) { case NETLBL_NLTYPE_ADDRSELECT: nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST); if (nla_a == NULL) return -ENOMEM; - netlbl_af4list_foreach_rcu(iter4, - &entry->type_def.addrsel->list4) { + netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) { struct netlbl_domaddr4_map *map4; struct in_addr addr_struct; @@ -310,13 +309,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, return ret_val; map4 = netlbl_domhsh_addr4_entry(iter4); ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, - map4->type); + map4->def.type); if (ret_val != 0) return ret_val; - switch (map4->type) { + switch (map4->def.type) { case NETLBL_NLTYPE_CIPSOV4: ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, - map4->type_def.cipsov4->doi); + map4->def.cipso->doi); if (ret_val != 0) return ret_val; break; @@ -325,8 +324,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, nla_nest_end(skb, nla_b); } #if IS_ENABLED(CONFIG_IPV6) - netlbl_af6list_foreach_rcu(iter6, - &entry->type_def.addrsel->list6) { + netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) { struct netlbl_domaddr6_map *map6; nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR); @@ -345,7 +343,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, return ret_val; map6 = netlbl_domhsh_addr6_entry(iter6); ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, - map6->type); + map6->def.type); if (ret_val != 0) return ret_val; @@ -356,14 +354,14 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb, nla_nest_end(skb, nla_a); break; case NETLBL_NLTYPE_UNLABELED: - ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); + ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); break; case NETLBL_NLTYPE_CIPSOV4: - ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type); + ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type); if (ret_val != 0) return ret_val; ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI, - entry->type_def.cipsov4->doi); + entry->def.cipso->doi); break; } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index af35319..8f08974 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1541,7 +1541,7 @@ int __init netlbl_unlabel_defconf(void) entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) return -ENOMEM; - entry->type = NETLBL_NLTYPE_UNLABELED; + entry->def.type = NETLBL_NLTYPE_UNLABELED; ret_val = netlbl_domhsh_add_default(entry, &audit_info); if (ret_val != 0) return ret_val; -- cgit v0.10.2 From e0d407564b532d978b03ceccebd224a05d02f111 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 3 Aug 2013 10:30:05 +0100 Subject: ARM: fix a cockup in 48be69a02 (ARM: move signal handlers into a vdso-like page) Unfortunately, I never committed the fix to a nasty oops which can occur as a result of that commit: ------------[ cut here ]------------ kernel BUG at /home/olof/work/batch/include/linux/mm.h:414! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 490 Comm: killall5 Not tainted 3.11.0-rc3-00288-gabe0308 #53 task: e90acac0 ti: e9be8000 task.ti: e9be8000 PC is at special_mapping_fault+0xa4/0xc4 LR is at __do_fault+0x68/0x48c This doesn't show up unless you do quite a bit of testing; a simple boot test does not do this, so all my nightly tests were passing fine. The reason for this is that install_special_mapping() expects the page array to stick around, and as this was only inserting one page which was stored on the kernel stack, that's why this was blowing up. Reported-by: Olof Johansson Tested-by: Olof Johansson Signed-off-by: Russell King diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 1e6c33d..d03b5bd 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -471,17 +471,18 @@ const char *arch_vma_name(struct vm_area_struct *vma) "[sigpage]" : NULL; } +static struct page *signal_page; extern struct page *get_signal_page(void); int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; - struct page *page; unsigned long addr; int ret; - page = get_signal_page(); - if (!page) + if (!signal_page) + signal_page = get_signal_page(); + if (!signal_page) return -ENOMEM; down_write(&mm->mmap_sem); @@ -493,7 +494,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) ret = install_special_mapping(mm, addr, PAGE_SIZE, VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, - &page); + &signal_page); if (ret == 0) mm->context.sigpage = addr; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 0f17e06..39e7105 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -614,35 +614,32 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) return 0; } -static struct page *signal_page; - struct page *get_signal_page(void) { - if (!signal_page) { - unsigned long ptr; - unsigned offset; - void *addr; + unsigned long ptr; + unsigned offset; + struct page *page; + void *addr; - signal_page = alloc_pages(GFP_KERNEL, 0); + page = alloc_pages(GFP_KERNEL, 0); - if (!signal_page) - return NULL; + if (!page) + return NULL; - addr = page_address(signal_page); + addr = page_address(page); - /* Give the signal return code some randomness */ - offset = 0x200 + (get_random_int() & 0x7fc); - signal_return_offset = offset; + /* Give the signal return code some randomness */ + offset = 0x200 + (get_random_int() & 0x7fc); + signal_return_offset = offset; - /* - * Copy signal return handlers into the vector page, and - * set sigreturn to be a pointer to these. - */ - memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); + /* + * Copy signal return handlers into the vector page, and + * set sigreturn to be a pointer to these. + */ + memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); - ptr = (unsigned long)addr + offset; - flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); - } + ptr = (unsigned long)addr + offset; + flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); - return signal_page; + return page; } -- cgit v0.10.2 From 8c0cc8a5d90bc7373a7a9e7f7a40eb41f51e03fc Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 3 Aug 2013 10:39:51 +0100 Subject: ARM: fix nommu builds with 48be69a02 (ARM: move signal handlers into a vdso-like page) Olof reports that noMMU builds error out with: arch/arm/kernel/signal.c: In function 'setup_return': arch/arm/kernel/signal.c:413:25: error: 'mm_context_t' has no member named 'sigpage' This shows one of the evilnesses of IS_ENABLED(). Get rid of it here and replace it with #ifdef's - and as no noMMU platform can make use of sigpage, depend on CONIFG_MMU not CONFIG_ARM_MPU. Reported-by: Olof Johansson Signed-off-by: Russell King diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h index 9c9b307..56211f2 100644 --- a/arch/arm/include/asm/elf.h +++ b/arch/arm/include/asm/elf.h @@ -130,8 +130,10 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +#ifdef CONFIG_MMU #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 struct linux_binprm; int arch_setup_additional_pages(struct linux_binprm *, int); +#endif #endif diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 39e7105..ab33042 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -402,7 +402,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, __put_user(sigreturn_codes[idx+1], rc+1)) return 1; - if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) { +#ifdef CONFIG_MMU + if (cpsr & MODE32_BIT) { struct mm_struct *mm = current->mm; /* @@ -412,7 +413,9 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig, */ retcode = mm->context.sigpage + signal_return_offset + (idx << 2) + thumb; - } else { + } else +#endif + { /* * Ensure that the instruction cache sees * the return code written onto the stack. -- cgit v0.10.2 From 5c52add19733eb36d8619713312f5604efef3502 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 30 Jul 2013 17:14:34 -0400 Subject: hwmon: (max6697) fix MAX6581 ideality Without this patch, the values for ideality (register 0x4b) and ideality selection mask (register 0x4c) are inverted. Signed-off-by: Vivien Didelot Cc: stable@vger.kernel.org # 3.9+ Signed-off-by: Guenter Roeck diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 328fb03..a41b5f3 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -605,12 +605,12 @@ static int max6697_init_chip(struct i2c_client *client) if (ret < 0) return ret; ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY, - pdata->ideality_mask >> 1); + pdata->ideality_value); if (ret < 0) return ret; ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY_SELECT, - pdata->ideality_value); + pdata->ideality_mask >> 1); if (ret < 0) return ret; } -- cgit v0.10.2 From b6bb1c63dd46c4a9cdccbf5b5db49386eb6759a9 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Sat, 3 Aug 2013 16:39:45 +0530 Subject: net: ethernet: davinci_emac: drop IRQF_DISABLED IRQF_DISABLED is a no-op by now and should be removed. Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 07b176b..1a222bce 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1568,8 +1568,7 @@ static int emac_dev_open(struct net_device *ndev) while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { if (devm_request_irq(&priv->pdev->dev, i, emac_irq, - IRQF_DISABLED, - ndev->name, ndev)) + 0, ndev->name, ndev)) goto rollback; } k++; -- cgit v0.10.2 From 4a99ab56cea66f9f67b9d07ace5cd40a336c8e6f Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 2 Aug 2013 23:15:54 -0400 Subject: qlcnic: Fix MAC address filter issue on 82xx adapter Driver was passing the address of a pointer instead of the pointer itself. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index d3f8797..82a03d3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -262,7 +262,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, mac_req = (struct qlcnic_mac_req *)&(req->words[0]); mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; - memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN); + memcpy(mac_req->mac_addr, uaddr, ETH_ALEN); vlan_req = (struct qlcnic_vlan_req *)&req->words[1]; vlan_req->vlan_id = cpu_to_le16(vlan_id); -- cgit v0.10.2 From e0d138d99507362e2e77b4ff61b546a8b63d60b0 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 2 Aug 2013 23:15:55 -0400 Subject: qlcnic: Fix ingress MAC learning o Delete MAC address from the adapter's filter table if the source MAC address of ingress packet matches. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 82a03d3..6946d35 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data) return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0; } +static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter, + struct qlcnic_filter *fil, + void *addr, u16 vlan_id) +{ + int ret; + u8 op; + + op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; + ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); + if (ret) + return; + + op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; + ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op); + if (!ret) { + hlist_del(&fil->fnode); + adapter->rx_fhash.fnum--; + } +} + +static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head, + void *addr, u16 vlan_id) +{ + struct qlcnic_filter *tmp_fil = NULL; + struct hlist_node *n; + + hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { + if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) && + tmp_fil->vlan_id == vlan_id) + return tmp_fil; + } + + return NULL; +} + void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, int loopback_pkt, u16 vlan_id) { struct ethhdr *phdr = (struct ethhdr *)(skb->data); struct qlcnic_filter *fil, *tmp_fil; - struct hlist_node *n; struct hlist_head *head; unsigned long time; u64 src_addr = 0; - u8 hindex, found = 0, op; + u8 hindex, op; int ret; memcpy(&src_addr, phdr->h_source, ETH_ALEN); + hindex = qlcnic_mac_hash(src_addr) & + (adapter->fhash.fbucket_size - 1); if (loopback_pkt) { if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax) return; - hindex = qlcnic_mac_hash(src_addr) & - (adapter->fhash.fbucket_size - 1); head = &(adapter->rx_fhash.fhead[hindex]); - hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && - tmp_fil->vlan_id == vlan_id) { - time = tmp_fil->ftime; - if (jiffies > (QLCNIC_READD_AGE * HZ + time)) - tmp_fil->ftime = jiffies; - return; - } + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) { + time = tmp_fil->ftime; + if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time)) + tmp_fil->ftime = jiffies; + return; } fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); @@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, adapter->rx_fhash.fnum++; spin_unlock(&adapter->rx_mac_learn_lock); } else { - hindex = qlcnic_mac_hash(src_addr) & - (adapter->fhash.fbucket_size - 1); - head = &(adapter->rx_fhash.fhead[hindex]); - spin_lock(&adapter->rx_mac_learn_lock); - hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && - tmp_fil->vlan_id == vlan_id) { - found = 1; - break; - } - } + head = &adapter->fhash.fhead[hindex]; - if (!found) { - spin_unlock(&adapter->rx_mac_learn_lock); - return; - } + spin_lock(&adapter->mac_learn_lock); - op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; - ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr, - vlan_id, op); - if (!ret) { + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) { op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr, vlan_id, op); if (!ret) { - hlist_del(&(tmp_fil->fnode)); - adapter->rx_fhash.fnum--; + hlist_del(&tmp_fil->fnode); + adapter->fhash.fnum--; } + + spin_unlock(&adapter->mac_learn_lock); + + return; } + + spin_unlock(&adapter->mac_learn_lock); + + head = &adapter->rx_fhash.fhead[hindex]; + + spin_lock(&adapter->rx_mac_learn_lock); + + tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id); + if (tmp_fil) + qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr, + vlan_id); + spin_unlock(&adapter->rx_mac_learn_lock); } } -- cgit v0.10.2 From f91bbcb0b82186b4d5669021b142c263b66505e1 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 2 Aug 2013 23:15:56 -0400 Subject: qlcnic: Free up memory in error path. Signed-off-by: Himanshu Madhani Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 0581a48..8d401ba 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -210,10 +210,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd) if (err) { dev_info(&adapter->pdev->dev, "Failed to set driver version in firmware\n"); - return -EIO; + err = -EIO; } - - return 0; + qlcnic_free_mbx_args(&cmd); + return err; } int -- cgit v0.10.2 From 01b91f4c31e434d08fa6b7f4d261cc4e98c0772a Mon Sep 17 00:00:00 2001 From: Pratik Pujar Date: Fri, 2 Aug 2013 23:15:57 -0400 Subject: qlcnic: Removed adapter series name from warning messages. Signed-off-by: Pratik Pujar Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index cc78d39..a849446 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2141,7 +2141,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x && !!qlcnic_use_msi) dev_warn(&pdev->dev, - "83xx adapter do not support MSI interrupts\n"); + "Device does not support MSI interrupts\n"); err = qlcnic_setup_intr(adapter, 0); if (err) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 56e85f9..5d40045 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -562,7 +562,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, INIT_LIST_HEAD(&adapter->vf_mc_list); if (!qlcnic_use_msi_x && !!qlcnic_use_msi) dev_warn(&adapter->pdev->dev, - "83xx adapter do not support MSI interrupts\n"); + "Device does not support MSI interrupts\n"); err = qlcnic_setup_intr(adapter, 1); if (err) { -- cgit v0.10.2 From 2e3ea7e763f2ce33bbede1cd5cb8d4cd60f3e11a Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 2 Aug 2013 23:15:58 -0400 Subject: qlcnic: Fix external loopback test. Driver was not handling external loopback diagnostic test request. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 05a847e..7a58e39 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -150,6 +150,7 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { "Link_Test_on_offline", "Interrupt_Test_offline", "Internal_Loopback_offline", + "External_Loopback_offline", "EEPROM_Test_offline" }; @@ -1026,8 +1027,15 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, if (data[3]) eth_test->flags |= ETH_TEST_FL_FAILED; - data[4] = qlcnic_eeprom_test(dev); - if (data[4]) + if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) { + data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE); + if (data[4]) + eth_test->flags |= ETH_TEST_FL_FAILED; + eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; + } + + data[5] = qlcnic_eeprom_test(dev); + if (data[5]) eth_test->flags |= ETH_TEST_FL_FAILED; } } -- cgit v0.10.2 From beb3d3a4d4830b1e090eedef0d0d7870639f09e0 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 2 Aug 2013 23:15:59 -0400 Subject: qlcnic: Fix link speed display for 82xx adapter o Do not obtain link speed from register when adapter link is down. Signed-off-by: Rajesh Borundia Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 7a58e39..ac42cde 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -301,9 +301,13 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, } if (netif_running(adapter->netdev) && ahw->has_link_events) { - reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn)); - speed = P3P_LINK_SPEED_VAL(pcifn, reg); - ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; + if (ahw->linkup) { + reg = QLCRD32(adapter, + P3P_LINK_SPEED_REG(pcifn)); + speed = P3P_LINK_SPEED_VAL(pcifn, reg); + ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; + } + ethtool_cmd_speed_set(ecmd, ahw->link_speed); ecmd->autoneg = ahw->link_autoneg; ecmd->duplex = ahw->link_duplex; -- cgit v0.10.2 From b1f5037f1b33a15fa2ad5c9c41837477465af063 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 2 Aug 2013 23:16:00 -0400 Subject: qlcnic: Fix link speed and duplex display for 83xx adapter o Set link speed and duplex to unknown when link is not up. Signed-off-by: Rajesh Borundia Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index bc483e1..94ff7a4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -2075,18 +2075,25 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter) static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter, u32 data[]) { + struct qlcnic_hardware_context *ahw = adapter->ahw; u8 link_status, duplex; /* link speed */ link_status = LSB(data[3]) & 1; - adapter->ahw->link_speed = MSW(data[2]); - adapter->ahw->link_autoneg = MSB(MSW(data[3])); - adapter->ahw->module_type = MSB(LSW(data[3])); - duplex = LSB(MSW(data[3])); - if (duplex) - adapter->ahw->link_duplex = DUPLEX_FULL; - else - adapter->ahw->link_duplex = DUPLEX_HALF; - adapter->ahw->has_link_events = 1; + if (link_status) { + ahw->link_speed = MSW(data[2]); + duplex = LSB(MSW(data[3])); + if (duplex) + ahw->link_duplex = DUPLEX_FULL; + else + ahw->link_duplex = DUPLEX_HALF; + } else { + ahw->link_speed = SPEED_UNKNOWN; + ahw->link_duplex = DUPLEX_UNKNOWN; + } + + ahw->link_autoneg = MSB(MSW(data[3])); + ahw->module_type = MSB(LSW(data[3])); + ahw->has_link_events = 1; qlcnic_advert_link_change(adapter, link_status); } -- cgit v0.10.2 From 4bd8e7385961932d863ea976a67f384c3a8302cb Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Fri, 2 Aug 2013 23:16:01 -0400 Subject: qlcnic: Fix for flash update failure on 83xx adapter Flash update routine was improperly checking register read API return value. Modify register read API and perform proper error check. Signed-off-by: Himanshu Madhani Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index f4bb8f5..221645e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1400,8 +1400,8 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64); #define ADDR_IN_RANGE(addr, low, high) \ (((addr) < (high)) && ((addr) >= (low))) -#define QLCRD32(adapter, off) \ - (adapter->ahw->hw_ops->read_reg)(adapter, off) +#define QLCRD32(adapter, off, err) \ + (adapter->ahw->hw_ops->read_reg)(adapter, off, err) #define QLCWR32(adapter, off, val) \ adapter->ahw->hw_ops->write_reg(adapter, off, val) @@ -1604,7 +1604,7 @@ struct qlcnic_nic_template { struct qlcnic_hardware_ops { void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t); void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t); - int (*read_reg) (struct qlcnic_adapter *, ulong); + int (*read_reg) (struct qlcnic_adapter *, ulong, int *); int (*write_reg) (struct qlcnic_adapter *, ulong, u32); void (*get_ocm_win) (struct qlcnic_hardware_context *); int (*get_mac_address) (struct qlcnic_adapter *, u8 *); @@ -1662,12 +1662,6 @@ static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf, adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size); } -static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, - ulong off) -{ - return adapter->ahw->hw_ops->read_reg(adapter, off); -} - static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 94ff7a4..92da998 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -228,17 +228,17 @@ static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr) return 0; } -int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr) +int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr, + int *err) { - int ret; struct qlcnic_hardware_context *ahw = adapter->ahw; - ret = __qlcnic_set_win_base(adapter, (u32) addr); - if (!ret) { + *err = __qlcnic_set_win_base(adapter, (u32) addr); + if (!*err) { return QLCRDX(ahw, QLCNIC_WILDCARD); } else { dev_err(&adapter->pdev->dev, - "%s failed, addr = 0x%x\n", __func__, (int)addr); + "%s failed, addr = 0x%lx\n", __func__, addr); return -EIO; } } @@ -561,7 +561,7 @@ void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter) void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, loff_t offset, size_t size) { - int ret; + int ret = 0; u32 data; if (qlcnic_api_lock(adapter)) { @@ -571,7 +571,7 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, return; } - ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset); + data = QLCRD32(adapter, (u32) offset, &ret); qlcnic_api_unlock(adapter); if (ret == -EIO) { @@ -580,7 +580,6 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf, __func__, (u32)offset); return; } - data = ret; memcpy(buf, &data, size); } @@ -2391,9 +2390,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, u8 *p_data, int count) { - int i, ret; - u32 word, range, flash_offset, addr = flash_addr; + u32 word, range, flash_offset, addr = flash_addr, ret; ulong indirect_add, direct_window; + int i, err = 0; flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1); if (addr & 0x3) { @@ -2411,10 +2410,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, /* Multi sector read */ for (i = 0; i < count; i++) { indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_add); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_add, &err); + if (err == -EIO) + return err; word = ret; *(u32 *)p_data = word; @@ -2435,10 +2433,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, /* Single sector read */ for (i = 0; i < count; i++) { indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_add); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_add, &err); + if (err == -EIO) + return err; word = ret; *(u32 *)p_data = word; @@ -2454,10 +2451,13 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter) { u32 status; int retries = QLC_83XX_FLASH_READ_RETRY_COUNT; + int err = 0; do { - status = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_STATUS); + status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err); + if (err == -EIO) + return err; + if ((status & QLC_83XX_FLASH_STATUS_READY) == QLC_83XX_FLASH_STATUS_READY) break; @@ -2509,7 +2509,8 @@ int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter) int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter) { - int ret, mfg_id; + int ret, err = 0; + u32 mfg_id; if (qlcnic_83xx_lock_flash(adapter)) return -EIO; @@ -2524,9 +2525,11 @@ int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter) return -EIO; } - mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA); - if (mfg_id == -EIO) - return -EIO; + mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err); + if (err == -EIO) { + qlcnic_83xx_unlock_flash(adapter); + return err; + } adapter->flash_mfg_id = (mfg_id & 0xFF); qlcnic_83xx_unlock_flash(adapter); @@ -2643,7 +2646,7 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, u32 *p_data, int count) { u32 temp; - int ret = -EIO; + int ret = -EIO, err = 0; if ((count < QLC_83XX_FLASH_WRITE_MIN) || (count > QLC_83XX_FLASH_WRITE_MAX)) { @@ -2652,8 +2655,10 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, return -EIO; } - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_SPI_CONTROL); + temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err); + if (err == -EIO) + return err; + qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL, (temp | QLC_83XX_FLASH_SPI_CTRL)); qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, @@ -2702,13 +2707,18 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr, return -EIO; } - ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS); + ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err); + if (err == -EIO) + return err; + if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) { dev_err(&adapter->pdev->dev, "%s: failed at %d\n", __func__, __LINE__); /* Operation failed, clear error bit */ - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLC_83XX_FLASH_SPI_CONTROL); + temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err); + if (err == -EIO) + return err; + qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL, (temp | QLC_83XX_FLASH_SPI_CTRL)); @@ -2830,6 +2840,7 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, { int i, j, ret = 0; u32 temp; + int err = 0; /* Check alignment */ if (addr & 0xF) @@ -2862,8 +2873,12 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, QLCNIC_TA_WRITE_START); for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qlcnic_83xx_rd_reg_indirect(adapter, - QLCNIC_MS_CTRL); + temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err); + if (err == -EIO) { + mutex_unlock(&adapter->ahw->mem_lock); + return err; + } + if ((temp & TA_CTL_BUSY) == 0) break; } @@ -2885,9 +2900,9 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr, int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, u8 *p_data, int count) { - int i, ret; - u32 word, addr = flash_addr; + u32 word, addr = flash_addr, ret; ulong indirect_addr; + int i, err = 0; if (qlcnic_83xx_lock_flash(adapter) != 0) return -EIO; @@ -2907,10 +2922,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, } indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr); - ret = qlcnic_83xx_rd_reg_indirect(adapter, - indirect_addr); - if (ret == -EIO) - return -EIO; + ret = QLCRD32(adapter, indirect_addr, &err); + if (err == -EIO) + return err; + word = ret; *(u32 *)p_data = word; p_data = p_data + 4; @@ -3376,7 +3391,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter, static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter) { - int ret; + int ret, err = 0; + u32 temp; qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR, QLC_83XX_FLASH_OEM_READ_SIG); @@ -3386,8 +3402,11 @@ static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter) if (ret) return -EIO; - ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA); - return ret & 0xFF; + temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err); + if (err == -EIO) + return err; + + return temp & 0xFF; } int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 2548d14..272f56a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -508,7 +508,7 @@ void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *); void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *); void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t); void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t); -int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong); +int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *); int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32); void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []); int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 51ab4b5..9f4b8d5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1303,8 +1303,11 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) { int i, j; u32 val = 0, val1 = 0, reg = 0; + int err = 0; - val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG); + val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val); for (j = 0; j < 2; j++) { @@ -1318,7 +1321,9 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_THRESHOLD; } for (i = 0; i < 8; i++) { - val = QLCRD32(adapter, reg + (i * 0x4)); + val = QLCRD32(adapter, reg + (i * 0x4), &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); @@ -1335,8 +1340,10 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_TC_MC_REG; } for (i = 0; i < 4; i++) { - val = QLCRD32(adapter, reg + (i * 0x4)); - dev_info(&adapter->pdev->dev, "0x%x ", val); + val = QLCRD32(adapter, reg + (i * 0x4), &err); + if (err == -EIO) + return; + dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); } @@ -1352,17 +1359,25 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) reg = QLC_83XX_PORT1_TC_STATS; } for (i = 7; i >= 0; i--) { - val = QLCRD32(adapter, reg); + val = QLCRD32(adapter, reg, &err); + if (err == -EIO) + return; val &= ~(0x7 << 29); /* Reset bits 29 to 31 */ QLCWR32(adapter, reg, (val | (i << 29))); - val = QLCRD32(adapter, reg); + val = QLCRD32(adapter, reg, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "0x%x ", val); } dev_info(&adapter->pdev->dev, "\n"); } - val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD); - val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD); + val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err); + if (err == -EIO) + return; + val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err); + if (err == -EIO) + return; dev_info(&adapter->pdev->dev, "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n", val, val1); @@ -1425,7 +1440,7 @@ static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter) static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev) { u32 heartbeat, peg_status; - int retries, ret = -EIO; + int retries, ret = -EIO, err = 0; retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT; p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev, @@ -1453,11 +1468,11 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev) "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n" "PEG_NET_4_PC: 0x%x\n", peg_status, QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3), - QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4)); + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err), + QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err)); if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) dev_err(&p_dev->pdev->dev, @@ -1501,18 +1516,22 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev) static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr, int duration, u32 mask, u32 status) { + int timeout_error, err = 0; u32 value; - int timeout_error; u8 retries; - value = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + value = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return err; retries = duration / 10; do { if ((value & mask) != status) { timeout_error = 1; msleep(duration / 10); - value = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + value = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return err; } else { timeout_error = 0; break; @@ -1606,9 +1625,12 @@ int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev) static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev, u32 raddr, u32 waddr) { - int value; + int err = 0; + u32 value; - value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr); + value = QLCRD32(p_dev, raddr, &err); + if (err == -EIO) + return; qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value); } @@ -1617,12 +1639,16 @@ static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev, u32 raddr, u32 waddr, struct qlc_83xx_rmw *p_rmw_hdr) { - int value; + int err = 0; + u32 value; - if (p_rmw_hdr->index_a) + if (p_rmw_hdr->index_a) { value = p_dev->ahw->reset.array[p_rmw_hdr->index_a]; - else - value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr); + } else { + value = QLCRD32(p_dev, raddr, &err); + if (err == -EIO) + return; + } value &= p_rmw_hdr->mask; value <<= p_rmw_hdr->shl; @@ -1675,7 +1701,7 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev, long delay; struct qlc_83xx_entry *entry; struct qlc_83xx_poll *poll; - int i; + int i, err = 0; unsigned long arg1, arg2; poll = (struct qlc_83xx_poll *)((char *)p_hdr + @@ -1699,10 +1725,12 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev, arg1, delay, poll->mask, poll->status)){ - qlcnic_83xx_rd_reg_indirect(p_dev, - arg1); - qlcnic_83xx_rd_reg_indirect(p_dev, - arg2); + QLCRD32(p_dev, arg1, &err); + if (err == -EIO) + return; + QLCRD32(p_dev, arg2, &err); + if (err == -EIO) + return; } } } @@ -1768,7 +1796,7 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev, struct qlc_83xx_entry_hdr *p_hdr) { long delay; - int index, i, j; + int index, i, j, err; struct qlc_83xx_quad_entry *entry; struct qlc_83xx_poll *poll; unsigned long addr; @@ -1788,7 +1816,10 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev, poll->mask, poll->status)){ index = p_dev->ahw->reset.array_index; addr = entry->dr_addr; - j = qlcnic_83xx_rd_reg_indirect(p_dev, addr); + j = QLCRD32(p_dev, addr, &err); + if (err == -EIO) + return; + p_dev->ahw->reset.array[index++] = j; if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 8d401ba..d09389b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -104,7 +104,7 @@ static u32 qlcnic_poll_rsp(struct qlcnic_adapter *adapter) { u32 rsp; - int timeout = 0; + int timeout = 0, err = 0; do { /* give atleast 1ms for firmware to respond */ @@ -113,7 +113,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT) return QLCNIC_CDRP_RSP_TIMEOUT; - rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET); + rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err); } while (!QLCNIC_CDRP_IS_RSP(rsp)); return rsp; @@ -122,7 +122,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter) int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd) { - int i; + int i, err = 0; u32 rsp; u32 signature; struct pci_dev *pdev = adapter->pdev; @@ -148,7 +148,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, dev_err(&pdev->dev, "card response timeout.\n"); cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT; } else if (rsp == QLCNIC_CDRP_RSP_FAIL) { - cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1)); + cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err); switch (cmd->rsp.arg[0]) { case QLCNIC_RCODE_INVALID_ARGS: fmt = "CDRP invalid args: [%d]\n"; @@ -175,7 +175,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS; for (i = 1; i < cmd->rsp.num; i++) - cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i)); + cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err); /* Release semaphore */ qlcnic_api_unlock(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index ac42cde..7aac23a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -267,7 +267,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, { struct qlcnic_hardware_context *ahw = adapter->ahw; u32 speed, reg; - int check_sfp_module = 0; + int check_sfp_module = 0, err = 0; u16 pcifn = ahw->pci_func; /* read which mode */ @@ -290,7 +290,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, } else if (adapter->ahw->port_type == QLCNIC_XGBE) { u32 val = 0; - val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR); + val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err); if (val == QLCNIC_PORT_MODE_802_3_AP) { ecmd->supported = SUPPORTED_1000baseT_Full; @@ -303,7 +303,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter, if (netif_running(adapter->netdev) && ahw->has_link_events) { if (ahw->linkup) { reg = QLCRD32(adapter, - P3P_LINK_SPEED_REG(pcifn)); + P3P_LINK_SPEED_REG(pcifn), &err); speed = P3P_LINK_SPEED_VAL(pcifn, reg); ahw->link_speed = speed * P3P_LINK_SPEED_MHZ; } @@ -468,13 +468,14 @@ static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter, u32 *regs_buff) { - int i, j = 0; + int i, j = 0, err = 0; for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++) regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]); j = 0; while (ext_diag_registers[j] != -1) - regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]); + regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++], + &err); return i; } @@ -524,13 +525,16 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) static u32 qlcnic_test_link(struct net_device *dev) { struct qlcnic_adapter *adapter = netdev_priv(dev); + int err = 0; u32 val; if (qlcnic_83xx_check(adapter)) { val = qlcnic_83xx_test_link(adapter); return (val & 1) ? 0 : 1; } - val = QLCRD32(adapter, CRB_XG_STATE_P3P); + val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err); + if (err == -EIO) + return err; val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val); return (val == XG_LINK_UP_P3P) ? 0 : 1; } @@ -663,6 +667,7 @@ qlcnic_get_pauseparam(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); int port = adapter->ahw->physical_port; + int err = 0; __u32 val; if (qlcnic_83xx_check(adapter)) { @@ -673,9 +678,13 @@ qlcnic_get_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return; /* get flow control settings */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); + if (err == -EIO) + return; pause->rx_pause = qlcnic_gb_get_rx_flowctl(val); - val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); + if (err == -EIO) + return; switch (port) { case 0: pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val)); @@ -695,7 +704,9 @@ qlcnic_get_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return; pause->rx_pause = 1; - val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); + if (err == -EIO) + return; if (port == 0) pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val)); else @@ -712,6 +723,7 @@ qlcnic_set_pauseparam(struct net_device *netdev, { struct qlcnic_adapter *adapter = netdev_priv(netdev); int port = adapter->ahw->physical_port; + int err = 0; __u32 val; if (qlcnic_83xx_check(adapter)) @@ -722,7 +734,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS)) return -EIO; /* set flow control */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port)); + val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err); + if (err == -EIO) + return err; if (pause->rx_pause) qlcnic_gb_rx_flowctl(val); @@ -733,7 +747,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, val); QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val); /* set autoneg */ - val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err); + if (err == -EIO) + return err; switch (port) { case 0: if (pause->tx_pause) @@ -769,7 +785,9 @@ qlcnic_set_pauseparam(struct net_device *netdev, if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS)) return -EIO; - val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL); + val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err); + if (err == -EIO) + return err; if (port == 0) { if (pause->tx_pause) qlcnic_xg_unset_xg0_mask(val); @@ -793,11 +811,14 @@ static int qlcnic_reg_test(struct net_device *dev) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 data_read; + int err = 0; if (qlcnic_83xx_check(adapter)) return qlcnic_83xx_reg_test(adapter); - data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0)); + data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err); + if (err == -EIO) + return err; if ((data_read & 0xffff) != adapter->pdev->vendor) return 1; @@ -1269,17 +1290,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 wol_cfg; + int err = 0; if (qlcnic_83xx_check(adapter)) return; wol->supported = 0; wol->wolopts = 0; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); + if (err == -EIO) + return; if (wol_cfg & (1UL << adapter->portnum)) wol->supported |= WAKE_MAGIC; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); if (wol_cfg & (1UL << adapter->portnum)) wol->wolopts |= WAKE_MAGIC; } @@ -1289,17 +1313,22 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct qlcnic_adapter *adapter = netdev_priv(dev); u32 wol_cfg; + int err = 0; if (qlcnic_83xx_check(adapter)) return -EOPNOTSUPP; if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); + if (err == -EIO) + return err; if (!(wol_cfg & (1 << adapter->portnum))) return -EOPNOTSUPP; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); + if (err == -EIO) + return err; if (wol->wolopts & WAKE_MAGIC) wol_cfg |= 1UL << adapter->portnum; else diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 4ed7e73..4d5f59b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -317,16 +317,20 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data) int qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) { - int done = 0, timeout = 0; + int timeout = 0; + int err = 0; + u32 done = 0; while (!done) { - done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem))); + done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), + &err); if (done == 1) break; if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { dev_err(&adapter->pdev->dev, "Failed to acquire sem=%d lock; holdby=%d\n", - sem, id_reg ? QLCRD32(adapter, id_reg) : -1); + sem, + id_reg ? QLCRD32(adapter, id_reg, &err) : -1); return -EIO; } msleep(1); @@ -341,19 +345,22 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem) { - QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem))); + int err = 0; + + QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err); } int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr) { + int err = 0; u32 data; if (qlcnic_82xx_check(adapter)) qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data); else { - data = qlcnic_83xx_rd_reg_indirect(adapter, addr); - if (data == -EIO) - return -EIO; + data = QLCRD32(adapter, addr, &err); + if (err == -EIO) + return err; } return data; } @@ -1159,7 +1166,8 @@ int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, return -EIO; } -int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) +int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off, + int *err) { unsigned long flags; int rv; @@ -1415,7 +1423,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) { - int offset, board_type, magic; + int offset, board_type, magic, err = 0; struct pci_dev *pdev = adapter->pdev; offset = QLCNIC_FW_MAGIC_OFFSET; @@ -1435,7 +1443,9 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter) adapter->ahw->board_type = board_type; if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { - u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); + u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err); + if (err == -EIO) + return err; if ((gpio & 0x8000) == 0) board_type = QLCNIC_BRDTYPE_P3P_10G_TP; } @@ -1475,10 +1485,13 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter) { u32 wol_cfg; + int err = 0; - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err); if (wol_cfg & (1UL << adapter->portnum)) { - wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG); + wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err); + if (err == -EIO) + return err; if (wol_cfg & (1 << adapter->portnum)) return 1; } @@ -1539,6 +1552,7 @@ void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf, loff_t offset, size_t size) { + int err = 0; u32 data; u64 qmdata; @@ -1546,7 +1560,7 @@ void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf, qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata); memcpy(buf, &qmdata, size); } else { - data = QLCRD32(adapter, offset); + data = QLCRD32(adapter, offset, &err); memcpy(buf, &data, size); } } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 2c22504..4a71b28 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -154,7 +154,7 @@ struct qlcnic_hardware_context; struct qlcnic_adapter; int qlcnic_82xx_start_firmware(struct qlcnic_adapter *); -int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong); +int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *); int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32); int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int); int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c index a202309..974d626 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c @@ -286,10 +286,11 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) { long timeout = 0; long done = 0; + int err = 0; cond_resched(); while (done == 0) { - done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS); + done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err); done &= 2; if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) { dev_err(&adapter->pdev->dev, @@ -304,6 +305,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter) static int do_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) { + int err = 0; + QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3); @@ -317,7 +320,9 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter, udelay(10); QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA); + *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err); + if (err == -EIO) + return err; return 0; } @@ -369,11 +374,11 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp) int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) { - int addr, val; + int addr, err = 0; int i, n, init_delay; struct crb_addr_pair *buf; unsigned offset; - u32 off; + u32 off, val; struct pci_dev *pdev = adapter->pdev; QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0); @@ -402,7 +407,9 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter) QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00); /* halt sre */ - val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000); + val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err); + if (err == -EIO) + return err; QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1))); /* halt epg */ @@ -719,10 +726,12 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter) static int qlcnic_has_mn(struct qlcnic_adapter *adapter) { - u32 capability; - capability = 0; + u32 capability = 0; + int err = 0; - capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY); + capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err); + if (err == -EIO) + return err; if (capability & QLCNIC_PEG_TUNE_MN_PRESENT) return 1; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index a849446..ee013fc 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -977,8 +977,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter) static int qlcnic_initialize_nic(struct qlcnic_adapter *adapter) { - int err; struct qlcnic_info nic_info; + int err = 0; memset(&nic_info, 0, sizeof(struct qlcnic_info)); err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func); @@ -993,7 +993,9 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter) if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) { u32 temp; - temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2); + temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err); + if (err == -EIO) + return err; adapter->ahw->extra_capability[0] = temp; } adapter->ahw->max_mac_filters = nic_info.max_mac_filters; @@ -3095,6 +3097,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) { u32 state = 0, heartbeat; u32 peg_status; + int err = 0; if (qlcnic_check_temp(adapter)) goto detach; @@ -3141,11 +3144,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) "PEG_NET_4_PC: 0x%x\n", peg_status, QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c), - QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c)); + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err), + QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err)); if (QLCNIC_FWERROR_CODE(peg_status) == 0x67) dev_err(&adapter->pdev->dev, "Firmware aborted with error code 0x00006700. " -- cgit v0.10.2 From adfb8e51332153016857194b85309150ac560286 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Aug 2013 09:03:29 -0400 Subject: drm/radeon: fix 64 bit divide in SI spm code Forgot to use the appropriate math64 function. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 7ad22e8..4182557 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1767,7 +1767,7 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe s64 temperature, t_slope, t_intercept, av, bv, t_ref; s64 tmp; - i_leakage = drm_int2fixp(ileakage) / 100; + i_leakage = div64_s64(drm_int2fixp(ileakage), 100); vddc = div64_s64(drm_int2fixp(v), 1000); temperature = div64_s64(drm_int2fixp(t), 1000); -- cgit v0.10.2 From 387aae6fdd737038e92d7bb40712bdf6dcb11945 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sun, 4 Aug 2013 11:30:25 -0700 Subject: tmpfs: fix SEEK_DATA/SEEK_HOLE regression Commit 46a1c2c7ae53 ("vfs: export lseek_execute() to modules") broke the tmpfs SEEK_DATA/SEEK_HOLE implementation, because vfs_setpos() converts the carefully prepared -ENXIO to -EINVAL. Other filesystems avoid it in error cases: do the same in tmpfs. Signed-off-by: Hugh Dickins Cc: Jie Liu Cc: Al Viro Signed-off-by: Linus Torvalds diff --git a/mm/shmem.c b/mm/shmem.c index a87990c..8335dbd 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1798,7 +1798,8 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence) } } - offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE); + if (offset >= 0) + offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE); mutex_unlock(&inode->i_mutex); return offset; } -- cgit v0.10.2 From c095ba7224d8edc71dcef0d655911399a8bd4a3f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 4 Aug 2013 13:46:46 -0700 Subject: Linux 3.11-rc4 diff --git a/Makefile b/Makefile index 95a8e55..f93d4f7 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 11 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Linux for Workgroups # *DOCUMENTATION* -- cgit v0.10.2 From 0ca06c0857aee11911f91621db14498496f2c2cd Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 24 Jul 2013 13:54:20 -0700 Subject: x86/mce: Pay no attention to 'F' bit in MCACOD when parsing 'UC' errors The 0x1000 bit of the MCACOD field of machine check MCi_STATUS registers is only defined for corrected errors (where it means that hardware may be filtering errors see SDM section 15.9.2.1). For uncorrected errors it may, or may not be set - so we should mask it out when checking for the architecturaly defined recoverable error signatures (see SDM 15.9.3.1 and 15.9.3.2) Acked-by: Naveen N. Rao Signed-off-by: Tony Luck diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 29e3093..aa97342 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -32,11 +32,20 @@ #define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */ #define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */ #define MCI_STATUS_AR (1ULL<<55) /* Action required */ -#define MCACOD 0xffff /* MCA Error Code */ + +/* + * Note that the full MCACOD field of IA32_MCi_STATUS MSR is + * bits 15:0. But bit 12 is the 'F' bit, defined for corrected + * errors to indicate that errors are being filtered by hardware. + * We should mask out bit 12 when looking for specific signatures + * of uncorrected errors - so the F bit is deliberately skipped + * in this #define. + */ +#define MCACOD 0xefff /* MCA Error Code */ /* Architecturally defined codes from SDM Vol. 3B Chapter 15 */ #define MCACOD_SCRUB 0x00C0 /* 0xC0-0xCF Memory Scrubbing */ -#define MCACOD_SCRUBMSK 0xfff0 +#define MCACOD_SCRUBMSK 0xeff0 /* Skip bit 12 ('F' bit) */ #define MCACOD_L3WB 0x017A /* L3 Explicit Writeback */ #define MCACOD_DATA 0x0134 /* Data Load */ #define MCACOD_INSTR 0x0150 /* Instruction Fetch */ -- cgit v0.10.2